| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Verification 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: secvfy.c,v 1.30 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 "keyhi.h" | |
| 13 #include "secasn1.h" | |
| 14 #include "secoid.h" | |
| 15 #include "pk11func.h" | |
| 16 #include "secdig.h" | |
| 17 #include "secerr.h" | |
| 18 #include "keyi.h" | |
| 19 | |
| 20 /* | |
| 21 ** Decrypt signature block using public key | |
| 22 ** Store the hash algorithm oid tag in *tagp | |
| 23 ** Store the digest in the digest buffer | |
| 24 ** Store the digest length in *digestlen | |
| 25 ** XXX this is assuming that the signature algorithm has WITH_RSA_ENCRYPTION | |
| 26 */ | |
| 27 static SECStatus | |
| 28 DecryptSigBlock(SECOidTag *tagp, unsigned char *digest, | |
| 29 unsigned int *digestlen, unsigned int maxdigestlen, | |
| 30 SECKEYPublicKey *key, const SECItem *sig, char *wincx) | |
| 31 { | |
| 32 SGNDigestInfo *di = NULL; | |
| 33 unsigned char *buf = NULL; | |
| 34 SECStatus rv; | |
| 35 SECOidTag tag; | |
| 36 SECItem it; | |
| 37 | |
| 38 if (key == NULL) goto loser; | |
| 39 | |
| 40 it.len = SECKEY_PublicKeyStrength(key); | |
| 41 if (!it.len) goto loser; | |
| 42 it.data = buf = (unsigned char *)PORT_Alloc(it.len); | |
| 43 if (!buf) goto loser; | |
| 44 | |
| 45 /* decrypt the block */ | |
| 46 rv = PK11_VerifyRecover(key, (SECItem *)sig, &it, wincx); | |
| 47 if (rv != SECSuccess) goto loser; | |
| 48 | |
| 49 di = SGN_DecodeDigestInfo(&it); | |
| 50 if (di == NULL) goto sigloser; | |
| 51 | |
| 52 /* | |
| 53 ** Finally we have the digest info; now we can extract the algorithm | |
| 54 ** ID and the signature block | |
| 55 */ | |
| 56 tag = SECOID_GetAlgorithmTag(&di->digestAlgorithm); | |
| 57 /* Check that tag is an appropriate algorithm */ | |
| 58 if (tag == SEC_OID_UNKNOWN) { | |
| 59 goto sigloser; | |
| 60 } | |
| 61 /* make sure the "parameters" are not too bogus. */ | |
| 62 if (di->digestAlgorithm.parameters.len > 2) { | |
| 63 goto sigloser; | |
| 64 } | |
| 65 if (di->digest.len > maxdigestlen) { | |
| 66 PORT_SetError(SEC_ERROR_OUTPUT_LEN); | |
| 67 goto loser; | |
| 68 } | |
| 69 PORT_Memcpy(digest, di->digest.data, di->digest.len); | |
| 70 *tagp = tag; | |
| 71 *digestlen = di->digest.len; | |
| 72 goto done; | |
| 73 | |
| 74 sigloser: | |
| 75 PORT_SetError(SEC_ERROR_BAD_SIGNATURE); | |
| 76 | |
| 77 loser: | |
| 78 rv = SECFailure; | |
| 79 | |
| 80 done: | |
| 81 if (di != NULL) SGN_DestroyDigestInfo(di); | |
| 82 if (buf != NULL) PORT_Free(buf); | |
| 83 | |
| 84 return rv; | |
| 85 } | |
| 86 | |
| 87 | |
| 88 struct VFYContextStr { | |
| 89 SECOidTag hashAlg; /* the hash algorithm */ | |
| 90 SECKEYPublicKey *key; | |
| 91 /* | |
| 92 * This buffer holds either the digest or the full signature | |
| 93 * depending on the type of the signature (key->keyType). It is | |
| 94 * defined as a union to make sure it always has enough space. | |
| 95 * | |
| 96 * Use the "buffer" union member to reference the buffer. | |
| 97 * Note: do not take the size of the "buffer" union member. Take | |
| 98 * the size of the union or some other union member instead. | |
| 99 */ | |
| 100 union { | |
| 101 unsigned char buffer[1]; | |
| 102 | |
| 103 /* the digest in the decrypted RSA signature */ | |
| 104 unsigned char rsadigest[HASH_LENGTH_MAX]; | |
| 105 /* the full DSA signature... 40 bytes */ | |
| 106 unsigned char dsasig[DSA_MAX_SIGNATURE_LEN]; | |
| 107 /* the full ECDSA signature */ | |
| 108 unsigned char ecdsasig[2 * MAX_ECKEY_LEN]; | |
| 109 } u; | |
| 110 unsigned int rsadigestlen; | |
| 111 void * wincx; | |
| 112 void *hashcx; | |
| 113 const SECHashObject *hashobj; | |
| 114 SECOidTag encAlg; /* enc alg */ | |
| 115 PRBool hasSignature; /* true if the signature was provided in the | |
| 116 * VFY_CreateContext call. If false, the | |
| 117 * signature must be provided with a | |
| 118 * VFY_EndWithSignature call. */ | |
| 119 }; | |
| 120 | |
| 121 /* | |
| 122 * decode the ECDSA or DSA signature from it's DER wrapping. | |
| 123 * The unwrapped/raw signature is placed in the buffer pointed | |
| 124 * to by dsig and has enough room for len bytes. | |
| 125 */ | |
| 126 static SECStatus | |
| 127 decodeECorDSASignature(SECOidTag algid, const SECItem *sig, unsigned char *dsig, | |
| 128 unsigned int len) { | |
| 129 SECItem *dsasig = NULL; /* also used for ECDSA */ | |
| 130 SECStatus rv=SECSuccess; | |
| 131 | |
| 132 if ((algid != SEC_OID_ANSIX9_DSA_SIGNATURE) && | |
| 133 (algid != SEC_OID_ANSIX962_EC_PUBLIC_KEY) ) { | |
| 134 if (sig->len != len) { | |
| 135 PORT_SetError(SEC_ERROR_BAD_DER); | |
| 136 return SECFailure; | |
| 137 } | |
| 138 | |
| 139 PORT_Memcpy(dsig, sig->data, sig->len); | |
| 140 return SECSuccess; | |
| 141 } | |
| 142 | |
| 143 if (algid == SEC_OID_ANSIX962_EC_PUBLIC_KEY) { | |
| 144 if (len > MAX_ECKEY_LEN * 2) { | |
| 145 PORT_SetError(SEC_ERROR_BAD_DER); | |
| 146 return SECFailure; | |
| 147 } | |
| 148 } | |
| 149 dsasig = DSAU_DecodeDerSigToLen((SECItem *)sig, len); | |
| 150 | |
| 151 if ((dsasig == NULL) || (dsasig->len != len)) { | |
| 152 rv = SECFailure; | |
| 153 } else { | |
| 154 PORT_Memcpy(dsig, dsasig->data, dsasig->len); | |
| 155 } | |
| 156 | |
| 157 if (dsasig != NULL) SECITEM_FreeItem(dsasig, PR_TRUE); | |
| 158 if (rv == SECFailure) PORT_SetError(SEC_ERROR_BAD_DER); | |
| 159 return rv; | |
| 160 } | |
| 161 | |
| 162 const SEC_ASN1Template hashParameterTemplate[] = | |
| 163 { | |
| 164 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECItem) }, | |
| 165 { SEC_ASN1_OBJECT_ID, 0 }, | |
| 166 { SEC_ASN1_SKIP_REST }, | |
| 167 { 0, } | |
| 168 }; | |
| 169 | |
| 170 /* | |
| 171 * Pulls the hash algorithm, signing algorithm, and key type out of a | |
| 172 * composite algorithm. | |
| 173 * | |
| 174 * sigAlg: the composite algorithm to dissect. | |
| 175 * hashalg: address of a SECOidTag which will be set with the hash algorithm. | |
| 176 * encalg: address of a SECOidTag which will be set with the signing alg. | |
| 177 * | |
| 178 * Returns: SECSuccess if the algorithm was acceptable, SECFailure if the | |
| 179 * algorithm was not found or was not a signing algorithm. | |
| 180 */ | |
| 181 SECStatus | |
| 182 sec_DecodeSigAlg(const SECKEYPublicKey *key, SECOidTag sigAlg, | |
| 183 const SECItem *param, SECOidTag *encalg, SECOidTag *hashalg) | |
| 184 { | |
| 185 int len; | |
| 186 PRArenaPool *arena; | |
| 187 SECStatus rv; | |
| 188 SECItem oid; | |
| 189 | |
| 190 PR_ASSERT(hashalg!=NULL); | |
| 191 PR_ASSERT(encalg!=NULL); | |
| 192 | |
| 193 switch (sigAlg) { | |
| 194 /* We probably shouldn't be generating MD2 signatures either */ | |
| 195 case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION: | |
| 196 *hashalg = SEC_OID_MD2; | |
| 197 break; | |
| 198 case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION: | |
| 199 *hashalg = SEC_OID_MD5; | |
| 200 break; | |
| 201 case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION: | |
| 202 case SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE: | |
| 203 case SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE: | |
| 204 *hashalg = SEC_OID_SHA1; | |
| 205 break; | |
| 206 case SEC_OID_PKCS1_RSA_ENCRYPTION: | |
| 207 case SEC_OID_PKCS1_RSA_PSS_SIGNATURE: | |
| 208 *hashalg = SEC_OID_UNKNOWN; /* get it from the RSA signature */ | |
| 209 break; | |
| 210 | |
| 211 case SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE: | |
| 212 case SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION: | |
| 213 case SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA224_DIGEST: | |
| 214 *hashalg = SEC_OID_SHA224; | |
| 215 break; | |
| 216 case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE: | |
| 217 case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION: | |
| 218 case SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA256_DIGEST: | |
| 219 *hashalg = SEC_OID_SHA256; | |
| 220 break; | |
| 221 case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE: | |
| 222 case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION: | |
| 223 *hashalg = SEC_OID_SHA384; | |
| 224 break; | |
| 225 case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE: | |
| 226 case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION: | |
| 227 *hashalg = SEC_OID_SHA512; | |
| 228 break; | |
| 229 | |
| 230 /* what about normal DSA? */ | |
| 231 case SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST: | |
| 232 case SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST: | |
| 233 case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE: | |
| 234 *hashalg = SEC_OID_SHA1; | |
| 235 break; | |
| 236 case SEC_OID_MISSI_DSS: | |
| 237 case SEC_OID_MISSI_KEA_DSS: | |
| 238 case SEC_OID_MISSI_KEA_DSS_OLD: | |
| 239 case SEC_OID_MISSI_DSS_OLD: | |
| 240 *hashalg = SEC_OID_SHA1; | |
| 241 break; | |
| 242 case SEC_OID_ANSIX962_ECDSA_SIGNATURE_RECOMMENDED_DIGEST: | |
| 243 /* This is an EC algorithm. Recommended means the largest | |
| 244 * hash algorithm that is not reduced by the keysize of | |
| 245 * the EC algorithm. Note that key strength is in bytes and | |
| 246 * algorithms are specified in bits. Never use an algorithm | |
| 247 * weaker than sha1. */ | |
| 248 len = SECKEY_PublicKeyStrength(key); | |
| 249 if (len < 28) { /* 28 bytes == 224 bits */ | |
| 250 *hashalg = SEC_OID_SHA1; | |
| 251 } else if (len < 32) { /* 32 bytes == 256 bits */ | |
| 252 *hashalg = SEC_OID_SHA224; | |
| 253 } else if (len < 48) { /* 48 bytes == 384 bits */ | |
| 254 *hashalg = SEC_OID_SHA256; | |
| 255 } else if (len < 64) { /* 48 bytes == 512 bits */ | |
| 256 *hashalg = SEC_OID_SHA384; | |
| 257 } else { | |
| 258 /* use the largest in this case */ | |
| 259 *hashalg = SEC_OID_SHA512; | |
| 260 } | |
| 261 break; | |
| 262 case SEC_OID_ANSIX962_ECDSA_SIGNATURE_SPECIFIED_DIGEST: | |
| 263 if (param == NULL) { | |
| 264 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); | |
| 265 return SECFailure; | |
| 266 } | |
| 267 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); | |
| 268 if (arena == NULL) { | |
| 269 return SECFailure; | |
| 270 } | |
| 271 rv = SEC_QuickDERDecodeItem(arena, &oid, hashParameterTemplate, param); | |
| 272 if (rv == SECSuccess) { | |
| 273 *hashalg = SECOID_FindOIDTag(&oid); | |
| 274 } | |
| 275 PORT_FreeArena(arena, PR_FALSE); | |
| 276 if (rv != SECSuccess) { | |
| 277 return rv; | |
| 278 } | |
| 279 /* only accept hash algorithms */ | |
| 280 if (HASH_GetHashTypeByOidTag(*hashalg) == HASH_AlgNULL) { | |
| 281 /* error set by HASH_GetHashTypeByOidTag */ | |
| 282 return SECFailure; | |
| 283 } | |
| 284 break; | |
| 285 /* we don't implement MD4 hashes */ | |
| 286 case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION: | |
| 287 default: | |
| 288 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); | |
| 289 return SECFailure; | |
| 290 } | |
| 291 /* get the "encryption" algorithm */ | |
| 292 switch (sigAlg) { | |
| 293 case SEC_OID_PKCS1_RSA_ENCRYPTION: | |
| 294 case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION: | |
| 295 case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION: | |
| 296 case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION: | |
| 297 case SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE: | |
| 298 case SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE: | |
| 299 case SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION: | |
| 300 case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION: | |
| 301 case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION: | |
| 302 case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION: | |
| 303 *encalg = SEC_OID_PKCS1_RSA_ENCRYPTION; | |
| 304 break; | |
| 305 case SEC_OID_PKCS1_RSA_PSS_SIGNATURE: | |
| 306 *encalg = SEC_OID_PKCS1_RSA_PSS_SIGNATURE; | |
| 307 break; | |
| 308 | |
| 309 /* what about normal DSA? */ | |
| 310 case SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST: | |
| 311 case SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST: | |
| 312 case SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA224_DIGEST: | |
| 313 case SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA256_DIGEST: | |
| 314 *encalg = SEC_OID_ANSIX9_DSA_SIGNATURE; | |
| 315 break; | |
| 316 case SEC_OID_MISSI_DSS: | |
| 317 case SEC_OID_MISSI_KEA_DSS: | |
| 318 case SEC_OID_MISSI_KEA_DSS_OLD: | |
| 319 case SEC_OID_MISSI_DSS_OLD: | |
| 320 *encalg = SEC_OID_MISSI_DSS; | |
| 321 break; | |
| 322 case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE: | |
| 323 case SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE: | |
| 324 case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE: | |
| 325 case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE: | |
| 326 case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE: | |
| 327 case SEC_OID_ANSIX962_ECDSA_SIGNATURE_RECOMMENDED_DIGEST: | |
| 328 case SEC_OID_ANSIX962_ECDSA_SIGNATURE_SPECIFIED_DIGEST: | |
| 329 *encalg = SEC_OID_ANSIX962_EC_PUBLIC_KEY; | |
| 330 break; | |
| 331 /* we don't implement MD4 hashes */ | |
| 332 case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION: | |
| 333 default: | |
| 334 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); | |
| 335 return SECFailure; | |
| 336 } | |
| 337 return SECSuccess; | |
| 338 } | |
| 339 | |
| 340 /* | |
| 341 * we can verify signatures that come from 2 different sources: | |
| 342 * one in with the signature contains a signature oid, and the other | |
| 343 * in which the signature is managed by a Public key (encAlg) oid | |
| 344 * and a hash oid. The latter is the more basic, so that's what | |
| 345 * our base vfyCreate function takes. | |
| 346 * | |
| 347 * There is one noteworthy corner case, if we are using an RSA key, and the | |
| 348 * signature block is provided, then the hashAlg can be specified as | |
| 349 * SEC_OID_UNKNOWN. In this case, verify will use the hash oid supplied | |
| 350 * in the RSA signature block. | |
| 351 */ | |
| 352 static VFYContext * | |
| 353 vfy_CreateContext(const SECKEYPublicKey *key, const SECItem *sig, | |
| 354 SECOidTag encAlg, SECOidTag hashAlg, SECOidTag *hash, void *wincx) | |
| 355 { | |
| 356 VFYContext *cx; | |
| 357 SECStatus rv; | |
| 358 unsigned int sigLen; | |
| 359 KeyType type; | |
| 360 | |
| 361 /* make sure the encryption algorithm matches the key type */ | |
| 362 /* RSA-PSS algorithm can be used with both rsaKey and rsaPssKey */ | |
| 363 type = seckey_GetKeyType(encAlg); | |
| 364 if ((key->keyType != type) && | |
| 365 ((key->keyType != rsaKey) || (type != rsaPssKey))) { | |
| 366 PORT_SetError(SEC_ERROR_PKCS7_KEYALG_MISMATCH); | |
| 367 return NULL; | |
| 368 } | |
| 369 | |
| 370 cx = (VFYContext*) PORT_ZAlloc(sizeof(VFYContext)); | |
| 371 if (cx == NULL) { | |
| 372 goto loser; | |
| 373 } | |
| 374 | |
| 375 cx->wincx = wincx; | |
| 376 cx->hasSignature = (sig != NULL); | |
| 377 cx->encAlg = encAlg; | |
| 378 cx->hashAlg = hashAlg; | |
| 379 cx->key = SECKEY_CopyPublicKey(key); | |
| 380 rv = SECSuccess; | |
| 381 if (sig) { | |
| 382 switch (type) { | |
| 383 case rsaKey: | |
| 384 rv = DecryptSigBlock(&cx->hashAlg, cx->u.buffer, &cx->rsadigestlen, | |
| 385 HASH_LENGTH_MAX, cx->key, sig, (char*)wincx); | |
| 386 if (cx->hashAlg != hashAlg && hashAlg != SEC_OID_UNKNOWN) { | |
| 387 PORT_SetError(SEC_ERROR_BAD_SIGNATURE); | |
| 388 rv = SECFailure; | |
| 389 } | |
| 390 break; | |
| 391 case dsaKey: | |
| 392 case ecKey: | |
| 393 sigLen = SECKEY_SignatureLen(key); | |
| 394 if (sigLen == 0) { | |
| 395 /* error set by SECKEY_SignatureLen */ | |
| 396 rv = SECFailure; | |
| 397 break; | |
| 398 } | |
| 399 rv = decodeECorDSASignature(encAlg, sig, cx->u.buffer, sigLen); | |
| 400 break; | |
| 401 default: | |
| 402 rv = SECFailure; | |
| 403 PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); | |
| 404 break; | |
| 405 } | |
| 406 } | |
| 407 | |
| 408 if (rv) goto loser; | |
| 409 | |
| 410 /* check hash alg again, RSA may have changed it.*/ | |
| 411 if (HASH_GetHashTypeByOidTag(cx->hashAlg) == HASH_AlgNULL) { | |
| 412 /* error set by HASH_GetHashTypeByOidTag */ | |
| 413 goto loser; | |
| 414 } | |
| 415 | |
| 416 if (hash) { | |
| 417 *hash = cx->hashAlg; | |
| 418 } | |
| 419 return cx; | |
| 420 | |
| 421 loser: | |
| 422 if (cx) { | |
| 423 VFY_DestroyContext(cx, PR_TRUE); | |
| 424 } | |
| 425 return 0; | |
| 426 } | |
| 427 | |
| 428 VFYContext * | |
| 429 VFY_CreateContext(SECKEYPublicKey *key, SECItem *sig, SECOidTag sigAlg, | |
| 430 void *wincx) | |
| 431 { | |
| 432 SECOidTag encAlg, hashAlg; | |
| 433 SECStatus rv = sec_DecodeSigAlg(key, sigAlg, NULL, &encAlg, &hashAlg); | |
| 434 if (rv != SECSuccess) { | |
| 435 return NULL; | |
| 436 } | |
| 437 return vfy_CreateContext(key, sig, encAlg, hashAlg, NULL, wincx); | |
| 438 } | |
| 439 | |
| 440 VFYContext * | |
| 441 VFY_CreateContextDirect(const SECKEYPublicKey *key, const SECItem *sig, | |
| 442 SECOidTag encAlg, SECOidTag hashAlg, | |
| 443 SECOidTag *hash, void *wincx) | |
| 444 { | |
| 445 return vfy_CreateContext(key, sig, encAlg, hashAlg, hash, wincx); | |
| 446 } | |
| 447 | |
| 448 VFYContext * | |
| 449 VFY_CreateContextWithAlgorithmID(const SECKEYPublicKey *key, const SECItem *sig, | |
| 450 const SECAlgorithmID *sigAlgorithm, SECOidTag *hash, void *wincx) | |
| 451 { | |
| 452 SECOidTag encAlg, hashAlg; | |
| 453 SECStatus rv = sec_DecodeSigAlg(key, | |
| 454 SECOID_GetAlgorithmTag((SECAlgorithmID *)sigAlgorithm), | |
| 455 &sigAlgorithm->parameters, &encAlg, &hashAlg); | |
| 456 if (rv != SECSuccess) { | |
| 457 return NULL; | |
| 458 } | |
| 459 return vfy_CreateContext(key, sig, encAlg, hashAlg, hash, wincx); | |
| 460 } | |
| 461 | |
| 462 void | |
| 463 VFY_DestroyContext(VFYContext *cx, PRBool freeit) | |
| 464 { | |
| 465 if (cx) { | |
| 466 if (cx->hashcx != NULL) { | |
| 467 (*cx->hashobj->destroy)(cx->hashcx, PR_TRUE); | |
| 468 cx->hashcx = NULL; | |
| 469 } | |
| 470 if (cx->key) { | |
| 471 SECKEY_DestroyPublicKey(cx->key); | |
| 472 } | |
| 473 if (freeit) { | |
| 474 PORT_ZFree(cx, sizeof(VFYContext)); | |
| 475 } | |
| 476 } | |
| 477 } | |
| 478 | |
| 479 SECStatus | |
| 480 VFY_Begin(VFYContext *cx) | |
| 481 { | |
| 482 if (cx->hashcx != NULL) { | |
| 483 (*cx->hashobj->destroy)(cx->hashcx, PR_TRUE); | |
| 484 cx->hashcx = NULL; | |
| 485 } | |
| 486 | |
| 487 cx->hashobj = HASH_GetHashObjectByOidTag(cx->hashAlg); | |
| 488 if (!cx->hashobj) | |
| 489 return SECFailure; /* error code is set */ | |
| 490 | |
| 491 cx->hashcx = (*cx->hashobj->create)(); | |
| 492 if (cx->hashcx == NULL) | |
| 493 return SECFailure; | |
| 494 | |
| 495 (*cx->hashobj->begin)(cx->hashcx); | |
| 496 return SECSuccess; | |
| 497 } | |
| 498 | |
| 499 SECStatus | |
| 500 VFY_Update(VFYContext *cx, const unsigned char *input, unsigned inputLen) | |
| 501 { | |
| 502 if (cx->hashcx == NULL) { | |
| 503 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 504 return SECFailure; | |
| 505 } | |
| 506 (*cx->hashobj->update)(cx->hashcx, input, inputLen); | |
| 507 return SECSuccess; | |
| 508 } | |
| 509 | |
| 510 SECStatus | |
| 511 VFY_EndWithSignature(VFYContext *cx, SECItem *sig) | |
| 512 { | |
| 513 unsigned char final[HASH_LENGTH_MAX]; | |
| 514 unsigned part; | |
| 515 SECItem hash,dsasig; /* dsasig is also used for ECDSA */ | |
| 516 SECStatus rv; | |
| 517 | |
| 518 if ((cx->hasSignature == PR_FALSE) && (sig == NULL)) { | |
| 519 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 520 return SECFailure; | |
| 521 } | |
| 522 | |
| 523 if (cx->hashcx == NULL) { | |
| 524 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 525 return SECFailure; | |
| 526 } | |
| 527 (*cx->hashobj->end)(cx->hashcx, final, &part, sizeof(final)); | |
| 528 switch (cx->key->keyType) { | |
| 529 case ecKey: | |
| 530 case dsaKey: | |
| 531 dsasig.data = cx->u.buffer; | |
| 532 dsasig.len = SECKEY_SignatureLen(cx->key); | |
| 533 if (dsasig.len == 0) { | |
| 534 return SECFailure; | |
| 535 } | |
| 536 if (sig) { | |
| 537 rv = decodeECorDSASignature(cx->encAlg, sig, dsasig.data, | |
| 538 dsasig.len); | |
| 539 if (rv != SECSuccess) { | |
| 540 PORT_SetError(SEC_ERROR_BAD_SIGNATURE); | |
| 541 return SECFailure; | |
| 542 } | |
| 543 } | |
| 544 hash.data = final; | |
| 545 hash.len = part; | |
| 546 if (PK11_Verify(cx->key,&dsasig,&hash,cx->wincx) != SECSuccess) { | |
| 547 PORT_SetError(SEC_ERROR_BAD_SIGNATURE); | |
| 548 return SECFailure; | |
| 549 } | |
| 550 break; | |
| 551 case rsaKey: | |
| 552 if (sig) { | |
| 553 SECOidTag hashid = SEC_OID_UNKNOWN; | |
| 554 rv = DecryptSigBlock(&hashid, cx->u.buffer, &cx->rsadigestlen, | |
| 555 HASH_LENGTH_MAX, cx->key, sig, (char*)cx->wincx); | |
| 556 if ((rv != SECSuccess) || (hashid != cx->hashAlg)) { | |
| 557 PORT_SetError(SEC_ERROR_BAD_SIGNATURE); | |
| 558 return SECFailure; | |
| 559 } | |
| 560 } | |
| 561 if ((part != cx->rsadigestlen) || | |
| 562 PORT_Memcmp(final, cx->u.buffer, part)) { | |
| 563 PORT_SetError(SEC_ERROR_BAD_SIGNATURE); | |
| 564 return SECFailure; | |
| 565 } | |
| 566 break; | |
| 567 default: | |
| 568 PORT_SetError(SEC_ERROR_BAD_SIGNATURE); | |
| 569 return SECFailure; /* shouldn't happen */ | |
| 570 } | |
| 571 return SECSuccess; | |
| 572 } | |
| 573 | |
| 574 SECStatus | |
| 575 VFY_End(VFYContext *cx) | |
| 576 { | |
| 577 return VFY_EndWithSignature(cx,NULL); | |
| 578 } | |
| 579 | |
| 580 /************************************************************************/ | |
| 581 /* | |
| 582 * Verify that a previously-computed digest matches a signature. | |
| 583 */ | |
| 584 static SECStatus | |
| 585 vfy_VerifyDigest(const SECItem *digest, const SECKEYPublicKey *key, | |
| 586 const SECItem *sig, SECOidTag encAlg, SECOidTag hashAlg, | |
| 587 void *wincx) | |
| 588 { | |
| 589 SECStatus rv; | |
| 590 VFYContext *cx; | |
| 591 SECItem dsasig; /* also used for ECDSA */ | |
| 592 | |
| 593 rv = SECFailure; | |
| 594 | |
| 595 cx = vfy_CreateContext(key, sig, encAlg, hashAlg, NULL, wincx); | |
| 596 if (cx != NULL) { | |
| 597 switch (key->keyType) { | |
| 598 case rsaKey: | |
| 599 if ((digest->len != cx->rsadigestlen) || | |
| 600 PORT_Memcmp(digest->data, cx->u.buffer, digest->len)) { | |
| 601 PORT_SetError(SEC_ERROR_BAD_SIGNATURE); | |
| 602 } else { | |
| 603 rv = SECSuccess; | |
| 604 } | |
| 605 break; | |
| 606 case dsaKey: | |
| 607 case ecKey: | |
| 608 dsasig.data = cx->u.buffer; | |
| 609 dsasig.len = SECKEY_SignatureLen(cx->key); | |
| 610 if (dsasig.len == 0) { | |
| 611 break; | |
| 612 } | |
| 613 if (PK11_Verify(cx->key, &dsasig, (SECItem *)digest, cx->wincx) | |
| 614 != SECSuccess) { | |
| 615 PORT_SetError(SEC_ERROR_BAD_SIGNATURE); | |
| 616 } else { | |
| 617 rv = SECSuccess; | |
| 618 } | |
| 619 break; | |
| 620 default: | |
| 621 break; | |
| 622 } | |
| 623 VFY_DestroyContext(cx, PR_TRUE); | |
| 624 } | |
| 625 return rv; | |
| 626 } | |
| 627 | |
| 628 SECStatus | |
| 629 VFY_VerifyDigestDirect(const SECItem *digest, const SECKEYPublicKey *key, | |
| 630 const SECItem *sig, SECOidTag encAlg, | |
| 631 SECOidTag hashAlg, void *wincx) | |
| 632 { | |
| 633 return vfy_VerifyDigest(digest, key, sig, encAlg, hashAlg, wincx); | |
| 634 } | |
| 635 | |
| 636 SECStatus | |
| 637 VFY_VerifyDigest(SECItem *digest, SECKEYPublicKey *key, SECItem *sig, | |
| 638 SECOidTag algid, void *wincx) | |
| 639 { | |
| 640 SECOidTag encAlg, hashAlg; | |
| 641 SECStatus rv = sec_DecodeSigAlg(key, algid, NULL, &encAlg, &hashAlg); | |
| 642 if (rv != SECSuccess) { | |
| 643 return SECFailure; | |
| 644 } | |
| 645 return vfy_VerifyDigest(digest, key, sig, encAlg, hashAlg, wincx); | |
| 646 } | |
| 647 | |
| 648 /* | |
| 649 * this function takes an optional hash oid, which the digest function | |
| 650 * will be compared with our target hash value. | |
| 651 */ | |
| 652 SECStatus | |
| 653 VFY_VerifyDigestWithAlgorithmID(const SECItem *digest, | |
| 654 const SECKEYPublicKey *key, const SECItem *sig, | |
| 655 const SECAlgorithmID *sigAlgorithm, | |
| 656 SECOidTag hashCmp, void *wincx) | |
| 657 { | |
| 658 SECOidTag encAlg, hashAlg; | |
| 659 SECStatus rv = sec_DecodeSigAlg(key, | |
| 660 SECOID_GetAlgorithmTag((SECAlgorithmID *)sigAlgorithm), | |
| 661 &sigAlgorithm->parameters, &encAlg, &hashAlg); | |
| 662 if (rv != SECSuccess) { | |
| 663 return rv; | |
| 664 } | |
| 665 if ( hashCmp != SEC_OID_UNKNOWN && | |
| 666 hashAlg != SEC_OID_UNKNOWN && | |
| 667 hashCmp != hashAlg) { | |
| 668 PORT_SetError(SEC_ERROR_BAD_SIGNATURE); | |
| 669 return SECFailure; | |
| 670 } | |
| 671 return vfy_VerifyDigest(digest, key, sig, encAlg, hashAlg, wincx); | |
| 672 } | |
| 673 | |
| 674 static SECStatus | |
| 675 vfy_VerifyData(const unsigned char *buf, int len, const SECKEYPublicKey *key, | |
| 676 const SECItem *sig, SECOidTag encAlg, SECOidTag hashAlg, | |
| 677 SECOidTag *hash, void *wincx) | |
| 678 { | |
| 679 SECStatus rv; | |
| 680 VFYContext *cx; | |
| 681 | |
| 682 cx = vfy_CreateContext(key, sig, encAlg, hashAlg, hash, wincx); | |
| 683 if (cx == NULL) | |
| 684 return SECFailure; | |
| 685 | |
| 686 rv = VFY_Begin(cx); | |
| 687 if (rv == SECSuccess) { | |
| 688 rv = VFY_Update(cx, (unsigned char *)buf, len); | |
| 689 if (rv == SECSuccess) | |
| 690 rv = VFY_End(cx); | |
| 691 } | |
| 692 | |
| 693 VFY_DestroyContext(cx, PR_TRUE); | |
| 694 return rv; | |
| 695 } | |
| 696 | |
| 697 SECStatus | |
| 698 VFY_VerifyDataDirect(const unsigned char *buf, int len, | |
| 699 const SECKEYPublicKey *key, const SECItem *sig, | |
| 700 SECOidTag encAlg, SECOidTag hashAlg, | |
| 701 SECOidTag *hash, void *wincx) | |
| 702 { | |
| 703 return vfy_VerifyData(buf, len, key, sig, encAlg, hashAlg, hash, wincx); | |
| 704 } | |
| 705 | |
| 706 SECStatus | |
| 707 VFY_VerifyData(const unsigned char *buf, int len, const SECKEYPublicKey *key, | |
| 708 const SECItem *sig, SECOidTag algid, void *wincx) | |
| 709 { | |
| 710 SECOidTag encAlg, hashAlg; | |
| 711 SECStatus rv = sec_DecodeSigAlg(key, algid, NULL, &encAlg, &hashAlg); | |
| 712 if (rv != SECSuccess) { | |
| 713 return rv; | |
| 714 } | |
| 715 return vfy_VerifyData(buf, len, key, sig, encAlg, hashAlg, NULL, wincx); | |
| 716 } | |
| 717 | |
| 718 SECStatus | |
| 719 VFY_VerifyDataWithAlgorithmID(const unsigned char *buf, int len, | |
| 720 const SECKEYPublicKey *key, | |
| 721 const SECItem *sig, | |
| 722 const SECAlgorithmID *sigAlgorithm, | |
| 723 SECOidTag *hash, void *wincx) | |
| 724 { | |
| 725 SECOidTag encAlg, hashAlg; | |
| 726 SECOidTag sigAlg = SECOID_GetAlgorithmTag((SECAlgorithmID *)sigAlgorithm); | |
| 727 SECStatus rv = sec_DecodeSigAlg(key, sigAlg, | |
| 728 &sigAlgorithm->parameters, &encAlg, &hashAlg); | |
| 729 if (rv != SECSuccess) { | |
| 730 return rv; | |
| 731 } | |
| 732 return vfy_VerifyData(buf, len, key, sig, encAlg, hashAlg, hash, wincx); | |
| 733 } | |
| OLD | NEW |