]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_apple_csp/lib/RSA_DSA_signature.cpp
Security-57337.40.85.tar.gz
[apple/security.git] / OSX / libsecurity_apple_csp / lib / RSA_DSA_signature.cpp
1 /*
2 * Copyright (c) 2000-2001,2011-2012,2014 Apple Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18
19 /*
20 * RSA_DSA_signature.cpp - openssl-based signature classes.
21 */
22
23 #include "RSA_DSA_signature.h"
24 #include "RSA_DSA_utils.h"
25 #include <stdexcept>
26 #include <assert.h>
27 #include <security_utilities/debugging.h>
28 #include <security_cdsa_utilities/cssmdata.h>
29 #include <opensslUtils/opensslUtils.h>
30 #include <opensslUtils/opensslAsn1.h>
31
32 #define rsaSigDebug(args...) secdebug("rsaSig", ## args)
33
34 static ModuleNexus<Mutex> gMutex;
35
36 RSASigner::~RSASigner()
37 {
38 StLock<Mutex> _(gMutex());
39 if(mWeMallocdRsaKey) {
40 assert(mRsaKey != NULL);
41 RSA_free(mRsaKey);
42 mRsaKey = NULL;
43 mWeMallocdRsaKey = false;
44 }
45 }
46
47 /* reusable init */
48 void RSASigner::signerInit(
49 const Context &context,
50 bool isSigning)
51 {
52 StLock<Mutex> _(gMutex());
53
54 setIsSigning(isSigning);
55 keyFromContext(context);
56
57 /* optional padding attribute */
58 uint32 padding;
59 bool padPresent = context.getInt(CSSM_ATTRIBUTE_PADDING, padding);
60 if(padPresent) {
61 /* padding specified in context, convert to openssl style */
62 switch(padding) {
63 case CSSM_PADDING_NONE:
64 mPadding = RSA_NO_PADDING;
65 break;
66 case CSSM_PADDING_PKCS1:
67 mPadding = RSA_PKCS1_PADDING;
68 break;
69 default:
70 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_PADDING);
71 }
72 }
73
74 /* optional blinding attribute */
75 uint32 blinding = context.getInt(CSSM_ATTRIBUTE_RSA_BLINDING);
76 if(blinding) {
77 if(RSA_blinding_on(mRsaKey, NULL) <= 0) {
78 /* actually no legit failures */
79 CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR);
80 }
81 }
82 else {
83 RSA_blinding_off(mRsaKey);
84 }
85
86 setInitFlag(true);
87 }
88
89 /* sign */
90 void RSASigner::sign(
91 const void *data,
92 size_t dataLen,
93 void *sig,
94 size_t *sigLen) /* IN/OUT */
95 {
96 StLock<Mutex> _(gMutex());
97
98 if(mRsaKey == NULL) {
99 CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR);
100 }
101
102 /* get encoded digest info */
103 CssmAutoData encodedInfo(alloc());
104 int irtn = generateDigestInfo(data,
105 dataLen,
106 digestAlg(),
107 encodedInfo,
108 RSA_size(mRsaKey));
109 if(irtn) {
110 rsaSigDebug("***digestInfo error\n");
111 throwOpensslErr(irtn);
112 }
113
114 /* signature := encrypted digest info */
115 irtn = RSA_private_encrypt((int)encodedInfo.length(),
116 (unsigned char *)encodedInfo.data(),
117 (unsigned char *)sig,
118 mRsaKey,
119 mPadding);
120 if(irtn < 0) {
121 throwRsaDsa("RSA_private_encrypt");
122 }
123 if((unsigned)irtn > *sigLen) {
124 rsaSigDebug("RSA_private_encrypt: sig overflow");
125 CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR);
126 }
127 *sigLen = (unsigned)irtn;
128 }
129
130 /* verify */
131 void RSASigner::verify(
132 const void *data,
133 size_t dataLen,
134 const void *sig,
135 size_t sigLen)
136 {
137 StLock<Mutex> _(gMutex());
138
139 const char *op = NULL;
140 bool throwSigVerify = false;
141
142 if(mRsaKey == NULL) {
143 CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR);
144 }
145
146 /* get encoded digest info */
147 CssmAutoData encodedInfo(alloc());
148 int irtn = generateDigestInfo(data,
149 dataLen,
150 digestAlg(),
151 encodedInfo,
152 RSA_size(mRsaKey));
153 if(irtn) {
154 rsaSigDebug("***digestInfo error\n");
155 CssmError::throwMe(/* FIXME */CSSMERR_CSP_INTERNAL_ERROR);
156 }
157
158 /* malloc decrypted signature */
159 unsigned char *decryptSig =
160 (unsigned char *)alloc().malloc(RSA_size(mRsaKey));
161 unsigned decryptSigLen;
162
163 /* signature should be encrypted digest info; decrypt the signature */
164 irtn = RSA_public_decrypt((int)sigLen,
165 (unsigned char *)sig,
166 decryptSig,
167 mRsaKey,
168 mPadding);
169 if(irtn < 0) {
170 op = "RSA_public_decrypt";
171 throwSigVerify = true;
172 goto abort;
173 }
174 decryptSigLen = (unsigned)irtn;
175 if(decryptSigLen != encodedInfo.length()) {
176 rsaSigDebug("***Decrypted signature length error (exp %ld, got %d)\n",
177 encodedInfo.length(), decryptSigLen);
178 throwSigVerify = true;
179 op = "RSA Sig length check";
180 goto abort;
181 }
182 if(memcmp(decryptSig, encodedInfo.data(), decryptSigLen)) {
183 rsaSigDebug("***Signature miscompare\n");
184 throwSigVerify = true;
185 op = "RSA Sig miscompare";
186 goto abort;
187 }
188 else {
189 irtn = 0;
190 }
191 abort:
192 if(decryptSig != NULL) {
193 alloc().free(decryptSig);
194 }
195 if(throwSigVerify) {
196 clearOpensslErrors();
197 CssmError::throwMe(CSSMERR_CSP_VERIFY_FAILED);
198 }
199 }
200
201 /* works for both, but only used for signing */
202 size_t RSASigner::maxSigSize()
203 {
204 StLock<Mutex> _(gMutex());
205 if(mRsaKey == NULL) {
206 return 0;
207 }
208 return RSA_size(mRsaKey);
209 }
210
211 /*
212 * obtain key from context, validate, convert to native RSA key
213 */
214 void RSASigner::keyFromContext(
215 const Context &context)
216 {
217 if(initFlag() && (mRsaKey != NULL)) {
218 /* reusing context, OK */
219 return;
220 }
221
222 CSSM_KEYCLASS keyClass;
223 CSSM_KEYUSE keyUse;
224 if(isSigning()) {
225 /* signing with private key */
226 keyClass = CSSM_KEYCLASS_PRIVATE_KEY;
227 keyUse = CSSM_KEYUSE_SIGN;
228 }
229 else {
230 /* verifying with public key */
231 keyClass = CSSM_KEYCLASS_PUBLIC_KEY;
232 keyUse = CSSM_KEYUSE_VERIFY;
233 }
234 if(mRsaKey == NULL) {
235 CSSM_DATA label = {0, NULL};
236 mRsaKey = contextToRsaKey(context,
237 mSession,
238 keyClass,
239 keyUse,
240 mWeMallocdRsaKey,
241 label);
242 /* cannot have label param for signing */
243 assert(label.Data == NULL);
244 }
245 }
246
247 DSASigner::~DSASigner()
248 {
249 if(mWeMallocdDsaKey) {
250 assert(mDsaKey != NULL);
251 DSA_free(mDsaKey);
252 mDsaKey = NULL;
253 mWeMallocdDsaKey = false;
254 }
255 }
256
257 /* reusable init */
258 void DSASigner::signerInit(
259 const Context &context,
260 bool isSigning)
261 {
262 setIsSigning(isSigning);
263 keyFromContext(context);
264 setInitFlag(true);
265 }
266
267 /* sign */
268 void DSASigner::sign(
269 const void *data,
270 size_t dataLen,
271 void *sig,
272 size_t *sigLen) /* IN/OUT */
273 {
274 if(mDsaKey == NULL) {
275 CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR);
276 }
277 if(mDsaKey->priv_key == NULL) {
278 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
279 }
280
281 /* get signature in internal format */
282 DSA_SIG *dsaSig = DSA_do_sign((unsigned char *)data, (int)dataLen, mDsaKey);
283 if(dsaSig == NULL) {
284 throwRsaDsa("DSA_do_sign");
285 }
286
287 /* DER encode the signature */
288 CssmAutoData encodedSig(alloc());
289 int irtn = DSASigEncode(dsaSig, encodedSig);
290 if(irtn) {
291 throwRsaDsa("DSASigEncode");
292 }
293 if(encodedSig.length() > *sigLen) {
294 throwRsaDsa("DSA sign overflow");
295 }
296 memmove(sig, encodedSig.data(), encodedSig.length());
297 *sigLen = encodedSig.length();
298 DSA_SIG_free(dsaSig);
299 }
300
301 /* verify */
302 void DSASigner::verify(
303 const void *data,
304 size_t dataLen,
305 const void *sig,
306 size_t sigLen)
307 {
308 bool throwSigVerify = false;
309 DSA_SIG *dsaSig = NULL;
310 CSSM_RETURN crtn = CSSM_OK;
311 int irtn;
312
313 if(mDsaKey == NULL) {
314 CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR);
315 }
316 if(mDsaKey->pub_key == NULL) {
317 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
318 }
319
320 /* incoming sig is DER encoded....decode into internal format */
321 dsaSig = DSA_SIG_new();
322 crtn = DSASigDecode(dsaSig, sig, (unsigned int)sigLen);
323 if(crtn) {
324 goto abort;
325 }
326
327 irtn = DSA_do_verify((unsigned char *)data, (int)dataLen, dsaSig, mDsaKey);
328 if(irtn != 1) {
329 throwSigVerify = true;
330 }
331
332 abort:
333 if(dsaSig != NULL) {
334 DSA_SIG_free(dsaSig);
335 }
336 if(throwSigVerify) {
337 clearOpensslErrors();
338 CssmError::throwMe(CSSMERR_CSP_VERIFY_FAILED);
339 }
340 else if(crtn) {
341 CssmError::throwMe(crtn);
342 }
343 }
344
345 /*
346 * Works for both, but only used for signing.
347 * DSA sig is a sequence of two 160-bit integers.
348 */
349 size_t DSASigner::maxSigSize()
350 {
351 if(mDsaKey == NULL) {
352 return 0;
353 }
354 size_t outSize;
355 size_t sizeOfOneInt;
356
357 sizeOfOneInt = (160 / 8) + // the raw contents
358 1 + // possible leading zero
359 2; // tag + length (assume DER, not BER)
360 outSize = (2 * sizeOfOneInt) + 5;
361 return outSize;
362 }
363
364 /*
365 * obtain key from context, validate, convert to native DSA key
366 */
367 void DSASigner::keyFromContext(
368 const Context &context)
369 {
370 if(initFlag() && (mDsaKey != NULL)) {
371 /* reusing context, OK */
372 return;
373 }
374
375 CSSM_KEYCLASS keyClass;
376 CSSM_KEYUSE keyUse;
377 if(isSigning()) {
378 /* signing with private key */
379 keyClass = CSSM_KEYCLASS_PRIVATE_KEY;
380 keyUse = CSSM_KEYUSE_SIGN;
381 }
382 else {
383 /* verifying with public key */
384 keyClass = CSSM_KEYCLASS_PUBLIC_KEY;
385 keyUse = CSSM_KEYUSE_VERIFY;
386 }
387 if(mDsaKey == NULL) {
388 mDsaKey = contextToDsaKey(context,
389 mSession,
390 keyClass,
391 keyUse,
392 mWeMallocdDsaKey);
393 }
394 }