Import from 1.9a8 tarball
[mozilla-nss.git] / security / nss / lib / cryptohi / secsign.c
blob22135fc2b829ee2fca1b58e62c72b2ef75f1ed9e
1 /*
2 * Signature stuff.
4 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
15 * License.
17 * The Original Code is the Netscape security libraries.
19 * The Initial Developer of the Original Code is
20 * Netscape Communications Corporation.
21 * Portions created by the Initial Developer are Copyright (C) 1994-2000
22 * the Initial Developer. All Rights Reserved.
24 * Contributor(s):
25 * Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
27 * Alternatively, the contents of this file may be used under the terms of
28 * either the GNU General Public License Version 2 or later (the "GPL"), or
29 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
40 /* $Id: secsign.c,v 1.18 2006/06/23 17:01:37 rrelyea%redhat.com Exp $ */
42 #include <stdio.h>
43 #include "cryptohi.h"
44 #include "sechash.h"
45 #include "secder.h"
46 #include "keyhi.h"
47 #include "secoid.h"
48 #include "secdig.h"
49 #include "pk11func.h"
50 #include "secerr.h"
51 #include "keyi.h"
53 struct SGNContextStr {
54 SECOidTag signalg;
55 SECOidTag hashalg;
56 void *hashcx;
57 const SECHashObject *hashobj;
58 SECKEYPrivateKey *key;
61 SGNContext *
62 SGN_NewContext(SECOidTag alg, SECKEYPrivateKey *key)
64 SGNContext *cx;
65 SECOidTag hashalg, signalg;
66 KeyType keyType;
67 SECStatus rv;
69 /* OK, map a PKCS #7 hash and encrypt algorithm into
70 * a standard hashing algorithm. Why did we pass in the whole
71 * PKCS #7 algTag if we were just going to change here you might
72 * ask. Well the answer is for some cards we may have to do the
73 * hashing on card. It may not support CKM_RSA_PKCS sign algorithm,
74 * it may just support CKM_RSA_PKCS_WITH_SHA1 and/or CKM_RSA_PKCS_WITH_MD5.
76 /* we have a private key, not a public key, so don't pass it in */
77 rv = sec_DecodeSigAlg(NULL, alg, NULL, &signalg, &hashalg);
78 if (rv != SECSuccess) {
79 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
80 return 0;
82 keyType = seckey_GetKeyType(signalg);
84 /* verify our key type */
85 if (key->keyType != keyType &&
86 !((key->keyType == dsaKey) && (keyType == fortezzaKey)) &&
87 !((key->keyType == fortezzaKey) && (keyType == dsaKey)) ) {
88 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
89 return 0;
92 #ifndef NSS_ECC_MORE_THAN_SUITE_B
93 if (key->keyType == ecKey) {
94 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
95 return 0;
97 #endif
99 cx = (SGNContext*) PORT_ZAlloc(sizeof(SGNContext));
100 if (cx) {
101 cx->hashalg = hashalg;
102 cx->signalg = signalg;
103 cx->key = key;
105 return cx;
108 void
109 SGN_DestroyContext(SGNContext *cx, PRBool freeit)
111 if (cx) {
112 if (cx->hashcx != NULL) {
113 (*cx->hashobj->destroy)(cx->hashcx, PR_TRUE);
114 cx->hashcx = NULL;
116 if (freeit) {
117 PORT_ZFree(cx, sizeof(SGNContext));
122 SECStatus
123 SGN_Begin(SGNContext *cx)
125 if (cx->hashcx != NULL) {
126 (*cx->hashobj->destroy)(cx->hashcx, PR_TRUE);
127 cx->hashcx = NULL;
130 cx->hashobj = HASH_GetHashObjectByOidTag(cx->hashalg);
131 if (!cx->hashobj)
132 return SECFailure; /* error code is already set */
134 cx->hashcx = (*cx->hashobj->create)();
135 if (cx->hashcx == NULL)
136 return SECFailure;
138 (*cx->hashobj->begin)(cx->hashcx);
139 return SECSuccess;
142 SECStatus
143 SGN_Update(SGNContext *cx, unsigned char *input, unsigned inputLen)
145 if (cx->hashcx == NULL) {
146 PORT_SetError(SEC_ERROR_INVALID_ARGS);
147 return SECFailure;
149 (*cx->hashobj->update)(cx->hashcx, input, inputLen);
150 return SECSuccess;
153 SECStatus
154 SGN_End(SGNContext *cx, SECItem *result)
156 unsigned char digest[HASH_LENGTH_MAX];
157 unsigned part1;
158 int signatureLen;
159 SECStatus rv;
160 SECItem digder, sigitem;
161 PRArenaPool *arena = 0;
162 SECKEYPrivateKey *privKey = cx->key;
163 SGNDigestInfo *di = 0;
165 result->data = 0;
166 digder.data = 0;
168 /* Finish up digest function */
169 if (cx->hashcx == NULL) {
170 PORT_SetError(SEC_ERROR_INVALID_ARGS);
171 return SECFailure;
173 (*cx->hashobj->end)(cx->hashcx, digest, &part1, sizeof(digest));
176 if (privKey->keyType == rsaKey) {
178 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
179 if ( !arena ) {
180 rv = SECFailure;
181 goto loser;
184 /* Construct digest info */
185 di = SGN_CreateDigestInfo(cx->hashalg, digest, part1);
186 if (!di) {
187 rv = SECFailure;
188 goto loser;
191 /* Der encode the digest as a DigestInfo */
192 rv = DER_Encode(arena, &digder, SGNDigestInfoTemplate, di);
193 if (rv != SECSuccess) {
194 goto loser;
196 } else {
197 digder.data = digest;
198 digder.len = part1;
202 ** Encrypt signature after constructing appropriate PKCS#1 signature
203 ** block
205 signatureLen = PK11_SignatureLen(privKey);
206 if (signatureLen <= 0) {
207 PORT_SetError(SEC_ERROR_INVALID_KEY);
208 rv = SECFailure;
209 goto loser;
211 sigitem.len = signatureLen;
212 sigitem.data = (unsigned char*) PORT_Alloc(signatureLen);
214 if (sigitem.data == NULL) {
215 rv = SECFailure;
216 goto loser;
219 rv = PK11_Sign(privKey, &sigitem, &digder);
220 if (rv != SECSuccess) {
221 PORT_Free(sigitem.data);
222 sigitem.data = NULL;
223 goto loser;
226 if ((cx->signalg == SEC_OID_ANSIX9_DSA_SIGNATURE) ||
227 (cx->signalg == SEC_OID_ANSIX962_EC_PUBLIC_KEY)) {
228 /* DSAU_EncodeDerSigWithLen works for DSA and ECDSA */
229 rv = DSAU_EncodeDerSigWithLen(result, &sigitem, sigitem.len);
230 PORT_Free(sigitem.data);
231 if (rv != SECSuccess)
232 goto loser;
233 } else {
234 result->len = sigitem.len;
235 result->data = sigitem.data;
238 loser:
239 SGN_DestroyDigestInfo(di);
240 if (arena != NULL) {
241 PORT_FreeArena(arena, PR_FALSE);
243 return rv;
246 /************************************************************************/
249 ** Sign a block of data returning in result a bunch of bytes that are the
250 ** signature. Returns zero on success, an error code on failure.
252 SECStatus
253 SEC_SignData(SECItem *res, unsigned char *buf, int len,
254 SECKEYPrivateKey *pk, SECOidTag algid)
256 SECStatus rv;
257 SGNContext *sgn;
260 sgn = SGN_NewContext(algid, pk);
262 if (sgn == NULL)
263 return SECFailure;
265 rv = SGN_Begin(sgn);
266 if (rv != SECSuccess)
267 goto loser;
269 rv = SGN_Update(sgn, buf, len);
270 if (rv != SECSuccess)
271 goto loser;
273 rv = SGN_End(sgn, res);
275 loser:
276 SGN_DestroyContext(sgn, PR_TRUE);
277 return rv;
280 /************************************************************************/
282 DERTemplate CERTSignedDataTemplate[] =
284 { DER_SEQUENCE,
285 0, NULL, sizeof(CERTSignedData) },
286 { DER_ANY,
287 offsetof(CERTSignedData,data), },
288 { DER_INLINE,
289 offsetof(CERTSignedData,signatureAlgorithm),
290 SECAlgorithmIDTemplate, },
291 { DER_BIT_STRING,
292 offsetof(CERTSignedData,signature), },
293 { 0, }
296 const SEC_ASN1Template CERT_SignedDataTemplate[] =
298 { SEC_ASN1_SEQUENCE,
299 0, NULL, sizeof(CERTSignedData) },
300 { SEC_ASN1_ANY,
301 offsetof(CERTSignedData,data), },
302 { SEC_ASN1_INLINE,
303 offsetof(CERTSignedData,signatureAlgorithm),
304 SECOID_AlgorithmIDTemplate, },
305 { SEC_ASN1_BIT_STRING,
306 offsetof(CERTSignedData,signature), },
307 { 0, }
310 SEC_ASN1_CHOOSER_IMPLEMENT(CERT_SignedDataTemplate)
313 SECStatus
314 SEC_DerSignData(PRArenaPool *arena, SECItem *result,
315 unsigned char *buf, int len, SECKEYPrivateKey *pk, SECOidTag algID)
317 SECItem it;
318 CERTSignedData sd;
319 SECStatus rv;
321 it.data = 0;
323 /* XXX We should probably have some asserts here to make sure the key type
324 * and algID match
327 if (algID == SEC_OID_UNKNOWN) {
328 switch(pk->keyType) {
329 case rsaKey:
330 algID = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION;
331 break;
332 case dsaKey:
333 algID = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST;
334 break;
335 case ecKey:
336 algID = SEC_OID_ANSIX962_ECDSA_SIGNATURE_WITH_SHA1_DIGEST;
337 break;
338 default:
339 PORT_SetError(SEC_ERROR_INVALID_KEY);
340 return SECFailure;
344 /* Sign input buffer */
345 rv = SEC_SignData(&it, buf, len, pk, algID);
346 if (rv) goto loser;
348 /* Fill out SignedData object */
349 PORT_Memset(&sd, 0, sizeof(sd));
350 sd.data.data = buf;
351 sd.data.len = len;
352 sd.signature.data = it.data;
353 sd.signature.len = it.len << 3; /* convert to bit string */
354 rv = SECOID_SetAlgorithmID(arena, &sd.signatureAlgorithm, algID, 0);
355 if (rv) goto loser;
357 /* DER encode the signed data object */
358 rv = DER_Encode(arena, result, CERTSignedDataTemplate, &sd);
359 /* FALL THROUGH */
361 loser:
362 PORT_Free(it.data);
363 return rv;
366 SECStatus
367 SGN_Digest(SECKEYPrivateKey *privKey,
368 SECOidTag algtag, SECItem *result, SECItem *digest)
370 int modulusLen;
371 SECStatus rv;
372 SECItem digder;
373 PRArenaPool *arena = 0;
374 SGNDigestInfo *di = 0;
377 result->data = 0;
379 if (privKey->keyType == rsaKey) {
381 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
382 if ( !arena ) {
383 rv = SECFailure;
384 goto loser;
387 /* Construct digest info */
388 di = SGN_CreateDigestInfo(algtag, digest->data, digest->len);
389 if (!di) {
390 rv = SECFailure;
391 goto loser;
394 /* Der encode the digest as a DigestInfo */
395 rv = DER_Encode(arena, &digder, SGNDigestInfoTemplate, di);
396 if (rv != SECSuccess) {
397 goto loser;
399 } else {
400 digder.data = digest->data;
401 digder.len = digest->len;
405 ** Encrypt signature after constructing appropriate PKCS#1 signature
406 ** block
408 modulusLen = PK11_SignatureLen(privKey);
409 if (modulusLen <= 0) {
410 PORT_SetError(SEC_ERROR_INVALID_KEY);
411 rv = SECFailure;
412 goto loser;
414 result->len = modulusLen;
415 result->data = (unsigned char*) PORT_Alloc(modulusLen);
417 if (result->data == NULL) {
418 rv = SECFailure;
419 goto loser;
422 rv = PK11_Sign(privKey, result, &digder);
423 if (rv != SECSuccess) {
424 PORT_Free(result->data);
425 result->data = NULL;
428 loser:
429 SGN_DestroyDigestInfo(di);
430 if (arena != NULL) {
431 PORT_FreeArena(arena, PR_FALSE);
433 return rv;
436 SECOidTag
437 SEC_GetSignatureAlgorithmOidTag(KeyType keyType, SECOidTag hashAlgTag)
439 SECOidTag sigTag = SEC_OID_UNKNOWN;
441 switch (keyType) {
442 case rsaKey:
443 switch (hashAlgTag) {
444 case SEC_OID_MD2:
445 sigTag = SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION; break;
446 case SEC_OID_MD5:
447 sigTag = SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION; break;
448 case SEC_OID_UNKNOWN: /* default for RSA if not specified */
449 case SEC_OID_SHA1:
450 sigTag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION; break;
451 case SEC_OID_SHA256:
452 sigTag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION; break;
453 case SEC_OID_SHA384:
454 sigTag = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION; break;
455 case SEC_OID_SHA512:
456 sigTag = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION; break;
457 default:
458 break;
460 break;
461 case dsaKey:
462 switch (hashAlgTag) {
463 case SEC_OID_UNKNOWN: /* default for DSA if not specified */
464 case SEC_OID_SHA1:
465 sigTag = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST; break;
466 default:
467 break;
469 break;
470 case ecKey:
471 switch (hashAlgTag) {
472 case SEC_OID_UNKNOWN: /* default for ECDSA if not specified */
473 case SEC_OID_SHA1:
474 sigTag = SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE; break;
475 case SEC_OID_SHA256:
476 sigTag = SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE; break;
477 case SEC_OID_SHA384:
478 sigTag = SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE; break;
479 case SEC_OID_SHA512:
480 sigTag = SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE; break;
481 default:
482 break;
484 default:
485 break;
487 return sigTag;