| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Signature stuff. | |
| 3 * | |
| 4 * This Source Code Form is subject to the terms of the Mozilla Public | |
| 5 * License, v. 2.0. If a copy of the MPL was not distributed with this | |
| 6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |
| 7 /* $Id: secsign.c,v 1.29 2012/06/25 21:48:39 rrelyea%redhat.com Exp $ */ | |
| 8 | |
| 9 #include <stdio.h> | |
| 10 #include "cryptohi.h" | |
| 11 #include "sechash.h" | |
| 12 #include "secder.h" | |
| 13 #include "keyhi.h" | |
| 14 #include "secoid.h" | |
| 15 #include "secdig.h" | |
| 16 #include "pk11func.h" | |
| 17 #include "secerr.h" | |
| 18 #include "keyi.h" | |
| 19 | |
| 20 struct SGNContextStr { | |
| 21 SECOidTag signalg; | |
| 22 SECOidTag hashalg; | |
| 23 void *hashcx; | |
| 24 const SECHashObject *hashobj; | |
| 25 SECKEYPrivateKey *key; | |
| 26 }; | |
| 27 | |
| 28 SGNContext * | |
| 29 SGN_NewContext(SECOidTag alg, SECKEYPrivateKey *key) | |
| 30 { | |
| 31 SGNContext *cx; | |
| 32 SECOidTag hashalg, signalg; | |
| 33 KeyType keyType; | |
| 34 SECStatus rv; | |
| 35 | |
| 36 /* OK, map a PKCS #7 hash and encrypt algorithm into | |
| 37 * a standard hashing algorithm. Why did we pass in the whole | |
| 38 * PKCS #7 algTag if we were just going to change here you might | |
| 39 * ask. Well the answer is for some cards we may have to do the | |
| 40 * hashing on card. It may not support CKM_RSA_PKCS sign algorithm, | |
| 41 * it may just support CKM_RSA_PKCS_WITH_SHA1 and/or CKM_RSA_PKCS_WITH_MD5. | |
| 42 */ | |
| 43 /* we have a private key, not a public key, so don't pass it in */ | |
| 44 rv = sec_DecodeSigAlg(NULL, alg, NULL, &signalg, &hashalg); | |
| 45 if (rv != SECSuccess) { | |
| 46 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); | |
| 47 return 0; | |
| 48 } | |
| 49 keyType = seckey_GetKeyType(signalg); | |
| 50 | |
| 51 /* verify our key type */ | |
| 52 if (key->keyType != keyType && | |
| 53 !((key->keyType == dsaKey) && (keyType == fortezzaKey)) ) { | |
| 54 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); | |
| 55 return 0; | |
| 56 } | |
| 57 | |
| 58 #ifndef NSS_ECC_MORE_THAN_SUITE_B | |
| 59 if (key->keyType == ecKey) { | |
| 60 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); | |
| 61 return 0; | |
| 62 } | |
| 63 #endif | |
| 64 | |
| 65 cx = (SGNContext*) PORT_ZAlloc(sizeof(SGNContext)); | |
| 66 if (cx) { | |
| 67 cx->hashalg = hashalg; | |
| 68 cx->signalg = signalg; | |
| 69 cx->key = key; | |
| 70 } | |
| 71 return cx; | |
| 72 } | |
| 73 | |
| 74 void | |
| 75 SGN_DestroyContext(SGNContext *cx, PRBool freeit) | |
| 76 { | |
| 77 if (cx) { | |
| 78 if (cx->hashcx != NULL) { | |
| 79 (*cx->hashobj->destroy)(cx->hashcx, PR_TRUE); | |
| 80 cx->hashcx = NULL; | |
| 81 } | |
| 82 if (freeit) { | |
| 83 PORT_ZFree(cx, sizeof(SGNContext)); | |
| 84 } | |
| 85 } | |
| 86 } | |
| 87 | |
| 88 SECStatus | |
| 89 SGN_Begin(SGNContext *cx) | |
| 90 { | |
| 91 if (cx->hashcx != NULL) { | |
| 92 (*cx->hashobj->destroy)(cx->hashcx, PR_TRUE); | |
| 93 cx->hashcx = NULL; | |
| 94 } | |
| 95 | |
| 96 cx->hashobj = HASH_GetHashObjectByOidTag(cx->hashalg); | |
| 97 if (!cx->hashobj) | |
| 98 return SECFailure; /* error code is already set */ | |
| 99 | |
| 100 cx->hashcx = (*cx->hashobj->create)(); | |
| 101 if (cx->hashcx == NULL) | |
| 102 return SECFailure; | |
| 103 | |
| 104 (*cx->hashobj->begin)(cx->hashcx); | |
| 105 return SECSuccess; | |
| 106 } | |
| 107 | |
| 108 SECStatus | |
| 109 SGN_Update(SGNContext *cx, const unsigned char *input, unsigned int inputLen) | |
| 110 { | |
| 111 if (cx->hashcx == NULL) { | |
| 112 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 113 return SECFailure; | |
| 114 } | |
| 115 (*cx->hashobj->update)(cx->hashcx, input, inputLen); | |
| 116 return SECSuccess; | |
| 117 } | |
| 118 | |
| 119 /* XXX Old template; want to expunge it eventually. */ | |
| 120 static DERTemplate SECAlgorithmIDTemplate[] = { | |
| 121 { DER_SEQUENCE, | |
| 122 0, NULL, sizeof(SECAlgorithmID) }, | |
| 123 { DER_OBJECT_ID, | |
| 124 offsetof(SECAlgorithmID,algorithm), }, | |
| 125 { DER_OPTIONAL | DER_ANY, | |
| 126 offsetof(SECAlgorithmID,parameters), }, | |
| 127 { 0, } | |
| 128 }; | |
| 129 | |
| 130 /* | |
| 131 * XXX OLD Template. Once all uses have been switched over to new one, | |
| 132 * remove this. | |
| 133 */ | |
| 134 static DERTemplate SGNDigestInfoTemplate[] = { | |
| 135 { DER_SEQUENCE, | |
| 136 0, NULL, sizeof(SGNDigestInfo) }, | |
| 137 { DER_INLINE, | |
| 138 offsetof(SGNDigestInfo,digestAlgorithm), | |
| 139 SECAlgorithmIDTemplate, }, | |
| 140 { DER_OCTET_STRING, | |
| 141 offsetof(SGNDigestInfo,digest), }, | |
| 142 { 0, } | |
| 143 }; | |
| 144 | |
| 145 SECStatus | |
| 146 SGN_End(SGNContext *cx, SECItem *result) | |
| 147 { | |
| 148 unsigned char digest[HASH_LENGTH_MAX]; | |
| 149 unsigned part1; | |
| 150 int signatureLen; | |
| 151 SECStatus rv; | |
| 152 SECItem digder, sigitem; | |
| 153 PRArenaPool *arena = 0; | |
| 154 SECKEYPrivateKey *privKey = cx->key; | |
| 155 SGNDigestInfo *di = 0; | |
| 156 | |
| 157 result->data = 0; | |
| 158 digder.data = 0; | |
| 159 | |
| 160 /* Finish up digest function */ | |
| 161 if (cx->hashcx == NULL) { | |
| 162 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 163 return SECFailure; | |
| 164 } | |
| 165 (*cx->hashobj->end)(cx->hashcx, digest, &part1, sizeof(digest)); | |
| 166 | |
| 167 | |
| 168 if (privKey->keyType == rsaKey) { | |
| 169 | |
| 170 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); | |
| 171 if ( !arena ) { | |
| 172 rv = SECFailure; | |
| 173 goto loser; | |
| 174 } | |
| 175 | |
| 176 /* Construct digest info */ | |
| 177 di = SGN_CreateDigestInfo(cx->hashalg, digest, part1); | |
| 178 if (!di) { | |
| 179 rv = SECFailure; | |
| 180 goto loser; | |
| 181 } | |
| 182 | |
| 183 /* Der encode the digest as a DigestInfo */ | |
| 184 rv = DER_Encode(arena, &digder, SGNDigestInfoTemplate, | |
| 185 di); | |
| 186 if (rv != SECSuccess) { | |
| 187 goto loser; | |
| 188 } | |
| 189 } else { | |
| 190 digder.data = digest; | |
| 191 digder.len = part1; | |
| 192 } | |
| 193 | |
| 194 /* | |
| 195 ** Encrypt signature after constructing appropriate PKCS#1 signature | |
| 196 ** block | |
| 197 */ | |
| 198 signatureLen = PK11_SignatureLen(privKey); | |
| 199 if (signatureLen <= 0) { | |
| 200 PORT_SetError(SEC_ERROR_INVALID_KEY); | |
| 201 rv = SECFailure; | |
| 202 goto loser; | |
| 203 } | |
| 204 sigitem.len = signatureLen; | |
| 205 sigitem.data = (unsigned char*) PORT_Alloc(signatureLen); | |
| 206 | |
| 207 if (sigitem.data == NULL) { | |
| 208 rv = SECFailure; | |
| 209 goto loser; | |
| 210 } | |
| 211 | |
| 212 rv = PK11_Sign(privKey, &sigitem, &digder); | |
| 213 if (rv != SECSuccess) { | |
| 214 PORT_Free(sigitem.data); | |
| 215 sigitem.data = NULL; | |
| 216 goto loser; | |
| 217 } | |
| 218 | |
| 219 if ((cx->signalg == SEC_OID_ANSIX9_DSA_SIGNATURE) || | |
| 220 (cx->signalg == SEC_OID_ANSIX962_EC_PUBLIC_KEY)) { | |
| 221 /* DSAU_EncodeDerSigWithLen works for DSA and ECDSA */ | |
| 222 rv = DSAU_EncodeDerSigWithLen(result, &sigitem, sigitem.len); | |
| 223 PORT_Free(sigitem.data); | |
| 224 if (rv != SECSuccess) | |
| 225 goto loser; | |
| 226 } else { | |
| 227 result->len = sigitem.len; | |
| 228 result->data = sigitem.data; | |
| 229 } | |
| 230 | |
| 231 loser: | |
| 232 SGN_DestroyDigestInfo(di); | |
| 233 if (arena != NULL) { | |
| 234 PORT_FreeArena(arena, PR_FALSE); | |
| 235 } | |
| 236 return rv; | |
| 237 } | |
| 238 | |
| 239 /************************************************************************/ | |
| 240 | |
| 241 /* | |
| 242 ** Sign a block of data returning in result a bunch of bytes that are the | |
| 243 ** signature. Returns zero on success, an error code on failure. | |
| 244 */ | |
| 245 SECStatus | |
| 246 SEC_SignData(SECItem *res, const unsigned char *buf, int len, | |
| 247 SECKEYPrivateKey *pk, SECOidTag algid) | |
| 248 { | |
| 249 SECStatus rv; | |
| 250 SGNContext *sgn; | |
| 251 | |
| 252 | |
| 253 sgn = SGN_NewContext(algid, pk); | |
| 254 | |
| 255 if (sgn == NULL) | |
| 256 return SECFailure; | |
| 257 | |
| 258 rv = SGN_Begin(sgn); | |
| 259 if (rv != SECSuccess) | |
| 260 goto loser; | |
| 261 | |
| 262 rv = SGN_Update(sgn, buf, len); | |
| 263 if (rv != SECSuccess) | |
| 264 goto loser; | |
| 265 | |
| 266 rv = SGN_End(sgn, res); | |
| 267 | |
| 268 loser: | |
| 269 SGN_DestroyContext(sgn, PR_TRUE); | |
| 270 return rv; | |
| 271 } | |
| 272 | |
| 273 /************************************************************************/ | |
| 274 | |
| 275 DERTemplate CERTSignedDataTemplate[] = | |
| 276 { | |
| 277 { DER_SEQUENCE, | |
| 278 0, NULL, sizeof(CERTSignedData) }, | |
| 279 { DER_ANY, | |
| 280 offsetof(CERTSignedData,data), }, | |
| 281 { DER_INLINE, | |
| 282 offsetof(CERTSignedData,signatureAlgorithm), | |
| 283 SECAlgorithmIDTemplate, }, | |
| 284 { DER_BIT_STRING, | |
| 285 offsetof(CERTSignedData,signature), }, | |
| 286 { 0, } | |
| 287 }; | |
| 288 | |
| 289 SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate) | |
| 290 | |
| 291 const SEC_ASN1Template CERT_SignedDataTemplate[] = | |
| 292 { | |
| 293 { SEC_ASN1_SEQUENCE, | |
| 294 0, NULL, sizeof(CERTSignedData) }, | |
| 295 { SEC_ASN1_ANY, | |
| 296 offsetof(CERTSignedData,data), }, | |
| 297 { SEC_ASN1_INLINE | SEC_ASN1_XTRN, | |
| 298 offsetof(CERTSignedData,signatureAlgorithm), | |
| 299 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate), }, | |
| 300 { SEC_ASN1_BIT_STRING, | |
| 301 offsetof(CERTSignedData,signature), }, | |
| 302 { 0, } | |
| 303 }; | |
| 304 | |
| 305 SEC_ASN1_CHOOSER_IMPLEMENT(CERT_SignedDataTemplate) | |
| 306 | |
| 307 | |
| 308 SECStatus | |
| 309 SEC_DerSignData(PRArenaPool *arena, SECItem *result, | |
| 310 const unsigned char *buf, int len, SECKEYPrivateKey *pk, | |
| 311 SECOidTag algID) | |
| 312 { | |
| 313 SECItem it; | |
| 314 CERTSignedData sd; | |
| 315 SECStatus rv; | |
| 316 | |
| 317 it.data = 0; | |
| 318 | |
| 319 /* XXX We should probably have some asserts here to make sure the key type | |
| 320 * and algID match | |
| 321 */ | |
| 322 | |
| 323 if (algID == SEC_OID_UNKNOWN) { | |
| 324 switch(pk->keyType) { | |
| 325 case rsaKey: | |
| 326 algID = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION; | |
| 327 break; | |
| 328 case dsaKey: | |
| 329 /* get Signature length (= q_len*2) and work from there */ | |
| 330 switch (PK11_SignatureLen(pk)) { | |
| 331 case 448: | |
| 332 algID = SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA224_DIGEST; | |
| 333 break; | |
| 334 case 512: | |
| 335 algID = SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA256_DIGEST; | |
| 336 break; | |
| 337 default: | |
| 338 algID = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST; | |
| 339 break; | |
| 340 } | |
| 341 break; | |
| 342 case ecKey: | |
| 343 algID = SEC_OID_ANSIX962_ECDSA_SIGNATURE_WITH_SHA1_DIGEST; | |
| 344 break; | |
| 345 default: | |
| 346 PORT_SetError(SEC_ERROR_INVALID_KEY); | |
| 347 return SECFailure; | |
| 348 } | |
| 349 } | |
| 350 | |
| 351 /* Sign input buffer */ | |
| 352 rv = SEC_SignData(&it, buf, len, pk, algID); | |
| 353 if (rv) goto loser; | |
| 354 | |
| 355 /* Fill out SignedData object */ | |
| 356 PORT_Memset(&sd, 0, sizeof(sd)); | |
| 357 sd.data.data = (unsigned char*) buf; | |
| 358 sd.data.len = len; | |
| 359 sd.signature.data = it.data; | |
| 360 sd.signature.len = it.len << 3; /* convert to bit string */ | |
| 361 rv = SECOID_SetAlgorithmID(arena, &sd.signatureAlgorithm, algID, 0); | |
| 362 if (rv) goto loser; | |
| 363 | |
| 364 /* DER encode the signed data object */ | |
| 365 rv = DER_Encode(arena, result, CERTSignedDataTemplate, &sd); | |
| 366 /* FALL THROUGH */ | |
| 367 | |
| 368 loser: | |
| 369 PORT_Free(it.data); | |
| 370 return rv; | |
| 371 } | |
| 372 | |
| 373 SECStatus | |
| 374 SGN_Digest(SECKEYPrivateKey *privKey, | |
| 375 SECOidTag algtag, SECItem *result, SECItem *digest) | |
| 376 { | |
| 377 int modulusLen; | |
| 378 SECStatus rv; | |
| 379 SECItem digder; | |
| 380 PRArenaPool *arena = 0; | |
| 381 SGNDigestInfo *di = 0; | |
| 382 | |
| 383 | |
| 384 result->data = 0; | |
| 385 | |
| 386 if (privKey->keyType == rsaKey) { | |
| 387 | |
| 388 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); | |
| 389 if ( !arena ) { | |
| 390 rv = SECFailure; | |
| 391 goto loser; | |
| 392 } | |
| 393 | |
| 394 /* Construct digest info */ | |
| 395 di = SGN_CreateDigestInfo(algtag, digest->data, digest->len); | |
| 396 if (!di) { | |
| 397 rv = SECFailure; | |
| 398 goto loser; | |
| 399 } | |
| 400 | |
| 401 /* Der encode the digest as a DigestInfo */ | |
| 402 rv = DER_Encode(arena, &digder, SGNDigestInfoTemplate, | |
| 403 di); | |
| 404 if (rv != SECSuccess) { | |
| 405 goto loser; | |
| 406 } | |
| 407 } else { | |
| 408 digder.data = digest->data; | |
| 409 digder.len = digest->len; | |
| 410 } | |
| 411 | |
| 412 /* | |
| 413 ** Encrypt signature after constructing appropriate PKCS#1 signature | |
| 414 ** block | |
| 415 */ | |
| 416 modulusLen = PK11_SignatureLen(privKey); | |
| 417 if (modulusLen <= 0) { | |
| 418 PORT_SetError(SEC_ERROR_INVALID_KEY); | |
| 419 rv = SECFailure; | |
| 420 goto loser; | |
| 421 } | |
| 422 result->len = modulusLen; | |
| 423 result->data = (unsigned char*) PORT_Alloc(modulusLen); | |
| 424 | |
| 425 if (result->data == NULL) { | |
| 426 rv = SECFailure; | |
| 427 goto loser; | |
| 428 } | |
| 429 | |
| 430 rv = PK11_Sign(privKey, result, &digder); | |
| 431 if (rv != SECSuccess) { | |
| 432 PORT_Free(result->data); | |
| 433 result->data = NULL; | |
| 434 } | |
| 435 | |
| 436 loser: | |
| 437 SGN_DestroyDigestInfo(di); | |
| 438 if (arena != NULL) { | |
| 439 PORT_FreeArena(arena, PR_FALSE); | |
| 440 } | |
| 441 return rv; | |
| 442 } | |
| 443 | |
| 444 SECOidTag | |
| 445 SEC_GetSignatureAlgorithmOidTag(KeyType keyType, SECOidTag hashAlgTag) | |
| 446 { | |
| 447 SECOidTag sigTag = SEC_OID_UNKNOWN; | |
| 448 | |
| 449 switch (keyType) { | |
| 450 case rsaKey: | |
| 451 switch (hashAlgTag) { | |
| 452 case SEC_OID_MD2: | |
| 453 sigTag = SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION; break; | |
| 454 case SEC_OID_MD5: | |
| 455 sigTag = SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION; break; | |
| 456 case SEC_OID_UNKNOWN: /* default for RSA if not specified */ | |
| 457 case SEC_OID_SHA1: | |
| 458 sigTag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION; break; | |
| 459 case SEC_OID_SHA224: | |
| 460 sigTag = SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION; break; | |
| 461 case SEC_OID_SHA256: | |
| 462 sigTag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION; break; | |
| 463 case SEC_OID_SHA384: | |
| 464 sigTag = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION; break; | |
| 465 case SEC_OID_SHA512: | |
| 466 sigTag = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION; break; | |
| 467 default: | |
| 468 break; | |
| 469 } | |
| 470 break; | |
| 471 case dsaKey: | |
| 472 switch (hashAlgTag) { | |
| 473 case SEC_OID_UNKNOWN: /* default for DSA if not specified */ | |
| 474 case SEC_OID_SHA1: | |
| 475 sigTag = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST; break; | |
| 476 case SEC_OID_SHA224: | |
| 477 sigTag = SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA224_DIGEST; break; | |
| 478 case SEC_OID_SHA256: | |
| 479 sigTag = SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA256_DIGEST; break; | |
| 480 default: | |
| 481 break; | |
| 482 } | |
| 483 break; | |
| 484 case ecKey: | |
| 485 switch (hashAlgTag) { | |
| 486 case SEC_OID_UNKNOWN: /* default for ECDSA if not specified */ | |
| 487 case SEC_OID_SHA1: | |
| 488 sigTag = SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE; break; | |
| 489 case SEC_OID_SHA224: | |
| 490 sigTag = SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE; break; | |
| 491 case SEC_OID_SHA256: | |
| 492 sigTag = SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE; break; | |
| 493 case SEC_OID_SHA384: | |
| 494 sigTag = SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE; break; | |
| 495 case SEC_OID_SHA512: | |
| 496 sigTag = SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE; break; | |
| 497 default: | |
| 498 break; | |
| 499 } | |
| 500 default: | |
| 501 break; | |
| 502 } | |
| 503 return sigTag; | |
| 504 } | |
| OLD | NEW |