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