1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/cryptohi/secvfy.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,778 @@ 1.4 +/* 1.5 + * Verification stuff. 1.6 + * 1.7 + * This Source Code Form is subject to the terms of the Mozilla Public 1.8 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.9 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.10 + 1.11 +#include <stdio.h> 1.12 +#include "cryptohi.h" 1.13 +#include "sechash.h" 1.14 +#include "keyhi.h" 1.15 +#include "secasn1.h" 1.16 +#include "secoid.h" 1.17 +#include "pk11func.h" 1.18 +#include "pkcs1sig.h" 1.19 +#include "secdig.h" 1.20 +#include "secerr.h" 1.21 +#include "keyi.h" 1.22 + 1.23 +/* 1.24 +** Recover the DigestInfo from an RSA PKCS#1 signature. 1.25 +** 1.26 +** If givenDigestAlg != SEC_OID_UNKNOWN, copy givenDigestAlg to digestAlgOut. 1.27 +** Otherwise, parse the DigestInfo structure and store the decoded digest 1.28 +** algorithm into digestAlgOut. 1.29 +** 1.30 +** Store the encoded DigestInfo into digestInfo. 1.31 +** Store the DigestInfo length into digestInfoLen. 1.32 +** 1.33 +** This function does *not* verify that the AlgorithmIdentifier in the 1.34 +** DigestInfo identifies givenDigestAlg or that the DigestInfo is encoded 1.35 +** correctly; verifyPKCS1DigestInfo does that. 1.36 +** 1.37 +** XXX this is assuming that the signature algorithm has WITH_RSA_ENCRYPTION 1.38 +*/ 1.39 +static SECStatus 1.40 +recoverPKCS1DigestInfo(SECOidTag givenDigestAlg, 1.41 + /*out*/ SECOidTag* digestAlgOut, 1.42 + /*out*/ unsigned char** digestInfo, 1.43 + /*out*/ unsigned int* digestInfoLen, 1.44 + SECKEYPublicKey* key, 1.45 + const SECItem* sig, void* wincx) 1.46 +{ 1.47 + SGNDigestInfo* di = NULL; 1.48 + SECItem it; 1.49 + PRBool rv = SECSuccess; 1.50 + 1.51 + PORT_Assert(digestAlgOut); 1.52 + PORT_Assert(digestInfo); 1.53 + PORT_Assert(digestInfoLen); 1.54 + PORT_Assert(key); 1.55 + PORT_Assert(key->keyType == rsaKey); 1.56 + PORT_Assert(sig); 1.57 + 1.58 + it.data = NULL; 1.59 + it.len = SECKEY_PublicKeyStrength(key); 1.60 + if (it.len != 0) { 1.61 + it.data = (unsigned char *)PORT_Alloc(it.len); 1.62 + } 1.63 + if (it.len == 0 || it.data == NULL ) { 1.64 + rv = SECFailure; 1.65 + } 1.66 + 1.67 + if (rv == SECSuccess) { 1.68 + /* decrypt the block */ 1.69 + rv = PK11_VerifyRecover(key, sig, &it, wincx); 1.70 + } 1.71 + 1.72 + if (rv == SECSuccess) { 1.73 + if (givenDigestAlg != SEC_OID_UNKNOWN) { 1.74 + /* We don't need to parse the DigestInfo if the caller gave us the 1.75 + * digest algorithm to use. Later verifyPKCS1DigestInfo will verify 1.76 + * that the DigestInfo identifies the given digest algorithm and 1.77 + * that the DigestInfo is encoded absolutely correctly. 1.78 + */ 1.79 + *digestInfoLen = it.len; 1.80 + *digestInfo = (unsigned char*)it.data; 1.81 + *digestAlgOut = givenDigestAlg; 1.82 + return SECSuccess; 1.83 + } 1.84 + } 1.85 + 1.86 + if (rv == SECSuccess) { 1.87 + /* The caller didn't specify a digest algorithm to use, so choose the 1.88 + * digest algorithm by parsing the AlgorithmIdentifier within the 1.89 + * DigestInfo. 1.90 + */ 1.91 + di = SGN_DecodeDigestInfo(&it); 1.92 + if (!di) { 1.93 + rv = SECFailure; 1.94 + } 1.95 + } 1.96 + 1.97 + if (rv == SECSuccess) { 1.98 + *digestAlgOut = SECOID_GetAlgorithmTag(&di->digestAlgorithm); 1.99 + if (*digestAlgOut == SEC_OID_UNKNOWN) { 1.100 + rv = SECFailure; 1.101 + } 1.102 + } 1.103 + 1.104 + if (di) { 1.105 + SGN_DestroyDigestInfo(di); 1.106 + } 1.107 + 1.108 + if (rv == SECSuccess) { 1.109 + *digestInfoLen = it.len; 1.110 + *digestInfo = (unsigned char*)it.data; 1.111 + } else { 1.112 + if (it.data) { 1.113 + PORT_Free(it.data); 1.114 + } 1.115 + *digestInfo = NULL; 1.116 + *digestInfoLen = 0; 1.117 + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); 1.118 + } 1.119 + 1.120 + return rv; 1.121 +} 1.122 + 1.123 +struct VFYContextStr { 1.124 + SECOidTag hashAlg; /* the hash algorithm */ 1.125 + SECKEYPublicKey *key; 1.126 + /* 1.127 + * This buffer holds either the digest or the full signature 1.128 + * depending on the type of the signature (key->keyType). It is 1.129 + * defined as a union to make sure it always has enough space. 1.130 + * 1.131 + * Use the "buffer" union member to reference the buffer. 1.132 + * Note: do not take the size of the "buffer" union member. Take 1.133 + * the size of the union or some other union member instead. 1.134 + */ 1.135 + union { 1.136 + unsigned char buffer[1]; 1.137 + 1.138 + /* the full DSA signature... 40 bytes */ 1.139 + unsigned char dsasig[DSA_MAX_SIGNATURE_LEN]; 1.140 + /* the full ECDSA signature */ 1.141 + unsigned char ecdsasig[2 * MAX_ECKEY_LEN]; 1.142 + } u; 1.143 + unsigned int pkcs1RSADigestInfoLen; 1.144 + /* the encoded DigestInfo from a RSA PKCS#1 signature */ 1.145 + unsigned char *pkcs1RSADigestInfo; 1.146 + void * wincx; 1.147 + void *hashcx; 1.148 + const SECHashObject *hashobj; 1.149 + SECOidTag encAlg; /* enc alg */ 1.150 + PRBool hasSignature; /* true if the signature was provided in the 1.151 + * VFY_CreateContext call. If false, the 1.152 + * signature must be provided with a 1.153 + * VFY_EndWithSignature call. */ 1.154 +}; 1.155 + 1.156 +static SECStatus 1.157 +verifyPKCS1DigestInfo(const VFYContext* cx, const SECItem* digest) 1.158 +{ 1.159 + SECItem pkcs1DigestInfo; 1.160 + pkcs1DigestInfo.data = cx->pkcs1RSADigestInfo; 1.161 + pkcs1DigestInfo.len = cx->pkcs1RSADigestInfoLen; 1.162 + return _SGN_VerifyPKCS1DigestInfo( 1.163 + cx->hashAlg, digest, &pkcs1DigestInfo, 1.164 + PR_TRUE /*XXX: unsafeAllowMissingParameters*/); 1.165 +} 1.166 + 1.167 +/* 1.168 + * decode the ECDSA or DSA signature from it's DER wrapping. 1.169 + * The unwrapped/raw signature is placed in the buffer pointed 1.170 + * to by dsig and has enough room for len bytes. 1.171 + */ 1.172 +static SECStatus 1.173 +decodeECorDSASignature(SECOidTag algid, const SECItem *sig, unsigned char *dsig, 1.174 + unsigned int len) { 1.175 + SECItem *dsasig = NULL; /* also used for ECDSA */ 1.176 + SECStatus rv=SECSuccess; 1.177 + 1.178 + if ((algid != SEC_OID_ANSIX9_DSA_SIGNATURE) && 1.179 + (algid != SEC_OID_ANSIX962_EC_PUBLIC_KEY) ) { 1.180 + if (sig->len != len) { 1.181 + PORT_SetError(SEC_ERROR_BAD_DER); 1.182 + return SECFailure; 1.183 + } 1.184 + 1.185 + PORT_Memcpy(dsig, sig->data, sig->len); 1.186 + return SECSuccess; 1.187 + } 1.188 + 1.189 + if (algid == SEC_OID_ANSIX962_EC_PUBLIC_KEY) { 1.190 + if (len > MAX_ECKEY_LEN * 2) { 1.191 + PORT_SetError(SEC_ERROR_BAD_DER); 1.192 + return SECFailure; 1.193 + } 1.194 + } 1.195 + dsasig = DSAU_DecodeDerSigToLen((SECItem *)sig, len); 1.196 + 1.197 + if ((dsasig == NULL) || (dsasig->len != len)) { 1.198 + rv = SECFailure; 1.199 + } else { 1.200 + PORT_Memcpy(dsig, dsasig->data, dsasig->len); 1.201 + } 1.202 + 1.203 + if (dsasig != NULL) SECITEM_FreeItem(dsasig, PR_TRUE); 1.204 + if (rv == SECFailure) PORT_SetError(SEC_ERROR_BAD_DER); 1.205 + return rv; 1.206 +} 1.207 + 1.208 +const SEC_ASN1Template hashParameterTemplate[] = 1.209 +{ 1.210 + { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECItem) }, 1.211 + { SEC_ASN1_OBJECT_ID, 0 }, 1.212 + { SEC_ASN1_SKIP_REST }, 1.213 + { 0, } 1.214 +}; 1.215 + 1.216 +/* 1.217 + * Pulls the hash algorithm, signing algorithm, and key type out of a 1.218 + * composite algorithm. 1.219 + * 1.220 + * sigAlg: the composite algorithm to dissect. 1.221 + * hashalg: address of a SECOidTag which will be set with the hash algorithm. 1.222 + * encalg: address of a SECOidTag which will be set with the signing alg. 1.223 + * 1.224 + * Returns: SECSuccess if the algorithm was acceptable, SECFailure if the 1.225 + * algorithm was not found or was not a signing algorithm. 1.226 + */ 1.227 +SECStatus 1.228 +sec_DecodeSigAlg(const SECKEYPublicKey *key, SECOidTag sigAlg, 1.229 + const SECItem *param, SECOidTag *encalg, SECOidTag *hashalg) 1.230 +{ 1.231 + int len; 1.232 + PLArenaPool *arena; 1.233 + SECStatus rv; 1.234 + SECItem oid; 1.235 + 1.236 + PR_ASSERT(hashalg!=NULL); 1.237 + PR_ASSERT(encalg!=NULL); 1.238 + 1.239 + switch (sigAlg) { 1.240 + /* We probably shouldn't be generating MD2 signatures either */ 1.241 + case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION: 1.242 + *hashalg = SEC_OID_MD2; 1.243 + break; 1.244 + case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION: 1.245 + *hashalg = SEC_OID_MD5; 1.246 + break; 1.247 + case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION: 1.248 + case SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE: 1.249 + case SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE: 1.250 + *hashalg = SEC_OID_SHA1; 1.251 + break; 1.252 + case SEC_OID_PKCS1_RSA_ENCRYPTION: 1.253 + case SEC_OID_PKCS1_RSA_PSS_SIGNATURE: 1.254 + *hashalg = SEC_OID_UNKNOWN; /* get it from the RSA signature */ 1.255 + break; 1.256 + 1.257 + case SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE: 1.258 + case SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION: 1.259 + case SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA224_DIGEST: 1.260 + *hashalg = SEC_OID_SHA224; 1.261 + break; 1.262 + case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE: 1.263 + case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION: 1.264 + case SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA256_DIGEST: 1.265 + *hashalg = SEC_OID_SHA256; 1.266 + break; 1.267 + case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE: 1.268 + case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION: 1.269 + *hashalg = SEC_OID_SHA384; 1.270 + break; 1.271 + case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE: 1.272 + case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION: 1.273 + *hashalg = SEC_OID_SHA512; 1.274 + break; 1.275 + 1.276 + /* what about normal DSA? */ 1.277 + case SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST: 1.278 + case SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST: 1.279 + case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE: 1.280 + *hashalg = SEC_OID_SHA1; 1.281 + break; 1.282 + case SEC_OID_MISSI_DSS: 1.283 + case SEC_OID_MISSI_KEA_DSS: 1.284 + case SEC_OID_MISSI_KEA_DSS_OLD: 1.285 + case SEC_OID_MISSI_DSS_OLD: 1.286 + *hashalg = SEC_OID_SHA1; 1.287 + break; 1.288 + case SEC_OID_ANSIX962_ECDSA_SIGNATURE_RECOMMENDED_DIGEST: 1.289 + /* This is an EC algorithm. Recommended means the largest 1.290 + * hash algorithm that is not reduced by the keysize of 1.291 + * the EC algorithm. Note that key strength is in bytes and 1.292 + * algorithms are specified in bits. Never use an algorithm 1.293 + * weaker than sha1. */ 1.294 + len = SECKEY_PublicKeyStrength(key); 1.295 + if (len < 28) { /* 28 bytes == 224 bits */ 1.296 + *hashalg = SEC_OID_SHA1; 1.297 + } else if (len < 32) { /* 32 bytes == 256 bits */ 1.298 + *hashalg = SEC_OID_SHA224; 1.299 + } else if (len < 48) { /* 48 bytes == 384 bits */ 1.300 + *hashalg = SEC_OID_SHA256; 1.301 + } else if (len < 64) { /* 48 bytes == 512 bits */ 1.302 + *hashalg = SEC_OID_SHA384; 1.303 + } else { 1.304 + /* use the largest in this case */ 1.305 + *hashalg = SEC_OID_SHA512; 1.306 + } 1.307 + break; 1.308 + case SEC_OID_ANSIX962_ECDSA_SIGNATURE_SPECIFIED_DIGEST: 1.309 + if (param == NULL) { 1.310 + PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); 1.311 + return SECFailure; 1.312 + } 1.313 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.314 + if (arena == NULL) { 1.315 + return SECFailure; 1.316 + } 1.317 + rv = SEC_QuickDERDecodeItem(arena, &oid, hashParameterTemplate, param); 1.318 + if (rv == SECSuccess) { 1.319 + *hashalg = SECOID_FindOIDTag(&oid); 1.320 + } 1.321 + PORT_FreeArena(arena, PR_FALSE); 1.322 + if (rv != SECSuccess) { 1.323 + return rv; 1.324 + } 1.325 + /* only accept hash algorithms */ 1.326 + if (HASH_GetHashTypeByOidTag(*hashalg) == HASH_AlgNULL) { 1.327 + /* error set by HASH_GetHashTypeByOidTag */ 1.328 + return SECFailure; 1.329 + } 1.330 + break; 1.331 + /* we don't implement MD4 hashes */ 1.332 + case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION: 1.333 + default: 1.334 + PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); 1.335 + return SECFailure; 1.336 + } 1.337 + /* get the "encryption" algorithm */ 1.338 + switch (sigAlg) { 1.339 + case SEC_OID_PKCS1_RSA_ENCRYPTION: 1.340 + case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION: 1.341 + case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION: 1.342 + case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION: 1.343 + case SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE: 1.344 + case SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE: 1.345 + case SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION: 1.346 + case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION: 1.347 + case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION: 1.348 + case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION: 1.349 + *encalg = SEC_OID_PKCS1_RSA_ENCRYPTION; 1.350 + break; 1.351 + case SEC_OID_PKCS1_RSA_PSS_SIGNATURE: 1.352 + *encalg = SEC_OID_PKCS1_RSA_PSS_SIGNATURE; 1.353 + break; 1.354 + 1.355 + /* what about normal DSA? */ 1.356 + case SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST: 1.357 + case SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST: 1.358 + case SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA224_DIGEST: 1.359 + case SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA256_DIGEST: 1.360 + *encalg = SEC_OID_ANSIX9_DSA_SIGNATURE; 1.361 + break; 1.362 + case SEC_OID_MISSI_DSS: 1.363 + case SEC_OID_MISSI_KEA_DSS: 1.364 + case SEC_OID_MISSI_KEA_DSS_OLD: 1.365 + case SEC_OID_MISSI_DSS_OLD: 1.366 + *encalg = SEC_OID_MISSI_DSS; 1.367 + break; 1.368 + case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE: 1.369 + case SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE: 1.370 + case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE: 1.371 + case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE: 1.372 + case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE: 1.373 + case SEC_OID_ANSIX962_ECDSA_SIGNATURE_RECOMMENDED_DIGEST: 1.374 + case SEC_OID_ANSIX962_ECDSA_SIGNATURE_SPECIFIED_DIGEST: 1.375 + *encalg = SEC_OID_ANSIX962_EC_PUBLIC_KEY; 1.376 + break; 1.377 + /* we don't implement MD4 hashes */ 1.378 + case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION: 1.379 + default: 1.380 + PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); 1.381 + return SECFailure; 1.382 + } 1.383 + return SECSuccess; 1.384 +} 1.385 + 1.386 +/* 1.387 + * we can verify signatures that come from 2 different sources: 1.388 + * one in with the signature contains a signature oid, and the other 1.389 + * in which the signature is managed by a Public key (encAlg) oid 1.390 + * and a hash oid. The latter is the more basic, so that's what 1.391 + * our base vfyCreate function takes. 1.392 + * 1.393 + * There is one noteworthy corner case, if we are using an RSA key, and the 1.394 + * signature block is provided, then the hashAlg can be specified as 1.395 + * SEC_OID_UNKNOWN. In this case, verify will use the hash oid supplied 1.396 + * in the RSA signature block. 1.397 + */ 1.398 +static VFYContext * 1.399 +vfy_CreateContext(const SECKEYPublicKey *key, const SECItem *sig, 1.400 + SECOidTag encAlg, SECOidTag hashAlg, SECOidTag *hash, void *wincx) 1.401 +{ 1.402 + VFYContext *cx; 1.403 + SECStatus rv; 1.404 + unsigned int sigLen; 1.405 + KeyType type; 1.406 + 1.407 + /* make sure the encryption algorithm matches the key type */ 1.408 + /* RSA-PSS algorithm can be used with both rsaKey and rsaPssKey */ 1.409 + type = seckey_GetKeyType(encAlg); 1.410 + if ((key->keyType != type) && 1.411 + ((key->keyType != rsaKey) || (type != rsaPssKey))) { 1.412 + PORT_SetError(SEC_ERROR_PKCS7_KEYALG_MISMATCH); 1.413 + return NULL; 1.414 + } 1.415 + 1.416 + cx = (VFYContext*) PORT_ZAlloc(sizeof(VFYContext)); 1.417 + if (cx == NULL) { 1.418 + goto loser; 1.419 + } 1.420 + 1.421 + cx->wincx = wincx; 1.422 + cx->hasSignature = (sig != NULL); 1.423 + cx->encAlg = encAlg; 1.424 + cx->hashAlg = hashAlg; 1.425 + cx->key = SECKEY_CopyPublicKey(key); 1.426 + cx->pkcs1RSADigestInfo = NULL; 1.427 + rv = SECSuccess; 1.428 + if (sig) { 1.429 + switch (type) { 1.430 + case rsaKey: 1.431 + rv = recoverPKCS1DigestInfo(hashAlg, &cx->hashAlg, 1.432 + &cx->pkcs1RSADigestInfo, 1.433 + &cx->pkcs1RSADigestInfoLen, 1.434 + cx->key, 1.435 + sig, wincx); 1.436 + break; 1.437 + case dsaKey: 1.438 + case ecKey: 1.439 + sigLen = SECKEY_SignatureLen(key); 1.440 + if (sigLen == 0) { 1.441 + /* error set by SECKEY_SignatureLen */ 1.442 + rv = SECFailure; 1.443 + break; 1.444 + } 1.445 + rv = decodeECorDSASignature(encAlg, sig, cx->u.buffer, sigLen); 1.446 + break; 1.447 + default: 1.448 + rv = SECFailure; 1.449 + PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); 1.450 + break; 1.451 + } 1.452 + } 1.453 + 1.454 + if (rv) goto loser; 1.455 + 1.456 + /* check hash alg again, RSA may have changed it.*/ 1.457 + if (HASH_GetHashTypeByOidTag(cx->hashAlg) == HASH_AlgNULL) { 1.458 + /* error set by HASH_GetHashTypeByOidTag */ 1.459 + goto loser; 1.460 + } 1.461 + 1.462 + if (hash) { 1.463 + *hash = cx->hashAlg; 1.464 + } 1.465 + return cx; 1.466 + 1.467 + loser: 1.468 + if (cx) { 1.469 + VFY_DestroyContext(cx, PR_TRUE); 1.470 + } 1.471 + return 0; 1.472 +} 1.473 + 1.474 +VFYContext * 1.475 +VFY_CreateContext(SECKEYPublicKey *key, SECItem *sig, SECOidTag sigAlg, 1.476 + void *wincx) 1.477 +{ 1.478 + SECOidTag encAlg, hashAlg; 1.479 + SECStatus rv = sec_DecodeSigAlg(key, sigAlg, NULL, &encAlg, &hashAlg); 1.480 + if (rv != SECSuccess) { 1.481 + return NULL; 1.482 + } 1.483 + return vfy_CreateContext(key, sig, encAlg, hashAlg, NULL, wincx); 1.484 +} 1.485 + 1.486 +VFYContext * 1.487 +VFY_CreateContextDirect(const SECKEYPublicKey *key, const SECItem *sig, 1.488 + SECOidTag encAlg, SECOidTag hashAlg, 1.489 + SECOidTag *hash, void *wincx) 1.490 +{ 1.491 + return vfy_CreateContext(key, sig, encAlg, hashAlg, hash, wincx); 1.492 +} 1.493 + 1.494 +VFYContext * 1.495 +VFY_CreateContextWithAlgorithmID(const SECKEYPublicKey *key, const SECItem *sig, 1.496 + const SECAlgorithmID *sigAlgorithm, SECOidTag *hash, void *wincx) 1.497 +{ 1.498 + SECOidTag encAlg, hashAlg; 1.499 + SECStatus rv = sec_DecodeSigAlg(key, 1.500 + SECOID_GetAlgorithmTag((SECAlgorithmID *)sigAlgorithm), 1.501 + &sigAlgorithm->parameters, &encAlg, &hashAlg); 1.502 + if (rv != SECSuccess) { 1.503 + return NULL; 1.504 + } 1.505 + return vfy_CreateContext(key, sig, encAlg, hashAlg, hash, wincx); 1.506 +} 1.507 + 1.508 +void 1.509 +VFY_DestroyContext(VFYContext *cx, PRBool freeit) 1.510 +{ 1.511 + if (cx) { 1.512 + if (cx->hashcx != NULL) { 1.513 + (*cx->hashobj->destroy)(cx->hashcx, PR_TRUE); 1.514 + cx->hashcx = NULL; 1.515 + } 1.516 + if (cx->key) { 1.517 + SECKEY_DestroyPublicKey(cx->key); 1.518 + } 1.519 + if (cx->pkcs1RSADigestInfo) { 1.520 + PORT_Free(cx->pkcs1RSADigestInfo); 1.521 + } 1.522 + if (freeit) { 1.523 + PORT_ZFree(cx, sizeof(VFYContext)); 1.524 + } 1.525 + } 1.526 +} 1.527 + 1.528 +SECStatus 1.529 +VFY_Begin(VFYContext *cx) 1.530 +{ 1.531 + if (cx->hashcx != NULL) { 1.532 + (*cx->hashobj->destroy)(cx->hashcx, PR_TRUE); 1.533 + cx->hashcx = NULL; 1.534 + } 1.535 + 1.536 + cx->hashobj = HASH_GetHashObjectByOidTag(cx->hashAlg); 1.537 + if (!cx->hashobj) 1.538 + return SECFailure; /* error code is set */ 1.539 + 1.540 + cx->hashcx = (*cx->hashobj->create)(); 1.541 + if (cx->hashcx == NULL) 1.542 + return SECFailure; 1.543 + 1.544 + (*cx->hashobj->begin)(cx->hashcx); 1.545 + return SECSuccess; 1.546 +} 1.547 + 1.548 +SECStatus 1.549 +VFY_Update(VFYContext *cx, const unsigned char *input, unsigned inputLen) 1.550 +{ 1.551 + if (cx->hashcx == NULL) { 1.552 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.553 + return SECFailure; 1.554 + } 1.555 + (*cx->hashobj->update)(cx->hashcx, input, inputLen); 1.556 + return SECSuccess; 1.557 +} 1.558 + 1.559 +SECStatus 1.560 +VFY_EndWithSignature(VFYContext *cx, SECItem *sig) 1.561 +{ 1.562 + unsigned char final[HASH_LENGTH_MAX]; 1.563 + unsigned part; 1.564 + SECItem hash,dsasig; /* dsasig is also used for ECDSA */ 1.565 + SECStatus rv; 1.566 + 1.567 + if ((cx->hasSignature == PR_FALSE) && (sig == NULL)) { 1.568 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.569 + return SECFailure; 1.570 + } 1.571 + 1.572 + if (cx->hashcx == NULL) { 1.573 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.574 + return SECFailure; 1.575 + } 1.576 + (*cx->hashobj->end)(cx->hashcx, final, &part, sizeof(final)); 1.577 + switch (cx->key->keyType) { 1.578 + case ecKey: 1.579 + case dsaKey: 1.580 + dsasig.data = cx->u.buffer; 1.581 + dsasig.len = SECKEY_SignatureLen(cx->key); 1.582 + if (dsasig.len == 0) { 1.583 + return SECFailure; 1.584 + } 1.585 + if (sig) { 1.586 + rv = decodeECorDSASignature(cx->encAlg, sig, dsasig.data, 1.587 + dsasig.len); 1.588 + if (rv != SECSuccess) { 1.589 + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); 1.590 + return SECFailure; 1.591 + } 1.592 + } 1.593 + hash.data = final; 1.594 + hash.len = part; 1.595 + if (PK11_Verify(cx->key,&dsasig,&hash,cx->wincx) != SECSuccess) { 1.596 + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); 1.597 + return SECFailure; 1.598 + } 1.599 + break; 1.600 + case rsaKey: 1.601 + { 1.602 + SECItem digest; 1.603 + digest.data = final; 1.604 + digest.len = part; 1.605 + if (sig) { 1.606 + SECOidTag hashid; 1.607 + PORT_Assert(cx->hashAlg != SEC_OID_UNKNOWN); 1.608 + rv = recoverPKCS1DigestInfo(cx->hashAlg, &hashid, 1.609 + &cx->pkcs1RSADigestInfo, 1.610 + &cx->pkcs1RSADigestInfoLen, 1.611 + cx->key, 1.612 + sig, cx->wincx); 1.613 + PORT_Assert(cx->hashAlg == hashid); 1.614 + if (rv != SECSuccess) { 1.615 + return SECFailure; 1.616 + } 1.617 + } 1.618 + return verifyPKCS1DigestInfo(cx, &digest); 1.619 + } 1.620 + default: 1.621 + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); 1.622 + return SECFailure; /* shouldn't happen */ 1.623 + } 1.624 + return SECSuccess; 1.625 +} 1.626 + 1.627 +SECStatus 1.628 +VFY_End(VFYContext *cx) 1.629 +{ 1.630 + return VFY_EndWithSignature(cx,NULL); 1.631 +} 1.632 + 1.633 +/************************************************************************/ 1.634 +/* 1.635 + * Verify that a previously-computed digest matches a signature. 1.636 + */ 1.637 +static SECStatus 1.638 +vfy_VerifyDigest(const SECItem *digest, const SECKEYPublicKey *key, 1.639 + const SECItem *sig, SECOidTag encAlg, SECOidTag hashAlg, 1.640 + void *wincx) 1.641 +{ 1.642 + SECStatus rv; 1.643 + VFYContext *cx; 1.644 + SECItem dsasig; /* also used for ECDSA */ 1.645 + 1.646 + rv = SECFailure; 1.647 + 1.648 + cx = vfy_CreateContext(key, sig, encAlg, hashAlg, NULL, wincx); 1.649 + if (cx != NULL) { 1.650 + switch (key->keyType) { 1.651 + case rsaKey: 1.652 + rv = verifyPKCS1DigestInfo(cx, digest); 1.653 + break; 1.654 + case dsaKey: 1.655 + case ecKey: 1.656 + dsasig.data = cx->u.buffer; 1.657 + dsasig.len = SECKEY_SignatureLen(cx->key); 1.658 + if (dsasig.len == 0) { 1.659 + break; 1.660 + } 1.661 + if (PK11_Verify(cx->key, &dsasig, (SECItem *)digest, cx->wincx) 1.662 + != SECSuccess) { 1.663 + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); 1.664 + } else { 1.665 + rv = SECSuccess; 1.666 + } 1.667 + break; 1.668 + default: 1.669 + break; 1.670 + } 1.671 + VFY_DestroyContext(cx, PR_TRUE); 1.672 + } 1.673 + return rv; 1.674 +} 1.675 + 1.676 +SECStatus 1.677 +VFY_VerifyDigestDirect(const SECItem *digest, const SECKEYPublicKey *key, 1.678 + const SECItem *sig, SECOidTag encAlg, 1.679 + SECOidTag hashAlg, void *wincx) 1.680 +{ 1.681 + return vfy_VerifyDigest(digest, key, sig, encAlg, hashAlg, wincx); 1.682 +} 1.683 + 1.684 +SECStatus 1.685 +VFY_VerifyDigest(SECItem *digest, SECKEYPublicKey *key, SECItem *sig, 1.686 + SECOidTag algid, void *wincx) 1.687 +{ 1.688 + SECOidTag encAlg, hashAlg; 1.689 + SECStatus rv = sec_DecodeSigAlg(key, algid, NULL, &encAlg, &hashAlg); 1.690 + if (rv != SECSuccess) { 1.691 + return SECFailure; 1.692 + } 1.693 + return vfy_VerifyDigest(digest, key, sig, encAlg, hashAlg, wincx); 1.694 +} 1.695 + 1.696 +/* 1.697 + * this function takes an optional hash oid, which the digest function 1.698 + * will be compared with our target hash value. 1.699 + */ 1.700 +SECStatus 1.701 +VFY_VerifyDigestWithAlgorithmID(const SECItem *digest, 1.702 + const SECKEYPublicKey *key, const SECItem *sig, 1.703 + const SECAlgorithmID *sigAlgorithm, 1.704 + SECOidTag hashCmp, void *wincx) 1.705 +{ 1.706 + SECOidTag encAlg, hashAlg; 1.707 + SECStatus rv = sec_DecodeSigAlg(key, 1.708 + SECOID_GetAlgorithmTag((SECAlgorithmID *)sigAlgorithm), 1.709 + &sigAlgorithm->parameters, &encAlg, &hashAlg); 1.710 + if (rv != SECSuccess) { 1.711 + return rv; 1.712 + } 1.713 + if ( hashCmp != SEC_OID_UNKNOWN && 1.714 + hashAlg != SEC_OID_UNKNOWN && 1.715 + hashCmp != hashAlg) { 1.716 + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); 1.717 + return SECFailure; 1.718 + } 1.719 + return vfy_VerifyDigest(digest, key, sig, encAlg, hashAlg, wincx); 1.720 +} 1.721 + 1.722 +static SECStatus 1.723 +vfy_VerifyData(const unsigned char *buf, int len, const SECKEYPublicKey *key, 1.724 + const SECItem *sig, SECOidTag encAlg, SECOidTag hashAlg, 1.725 + SECOidTag *hash, void *wincx) 1.726 +{ 1.727 + SECStatus rv; 1.728 + VFYContext *cx; 1.729 + 1.730 + cx = vfy_CreateContext(key, sig, encAlg, hashAlg, hash, wincx); 1.731 + if (cx == NULL) 1.732 + return SECFailure; 1.733 + 1.734 + rv = VFY_Begin(cx); 1.735 + if (rv == SECSuccess) { 1.736 + rv = VFY_Update(cx, (unsigned char *)buf, len); 1.737 + if (rv == SECSuccess) 1.738 + rv = VFY_End(cx); 1.739 + } 1.740 + 1.741 + VFY_DestroyContext(cx, PR_TRUE); 1.742 + return rv; 1.743 +} 1.744 + 1.745 +SECStatus 1.746 +VFY_VerifyDataDirect(const unsigned char *buf, int len, 1.747 + const SECKEYPublicKey *key, const SECItem *sig, 1.748 + SECOidTag encAlg, SECOidTag hashAlg, 1.749 + SECOidTag *hash, void *wincx) 1.750 +{ 1.751 + return vfy_VerifyData(buf, len, key, sig, encAlg, hashAlg, hash, wincx); 1.752 +} 1.753 + 1.754 +SECStatus 1.755 +VFY_VerifyData(const unsigned char *buf, int len, const SECKEYPublicKey *key, 1.756 + const SECItem *sig, SECOidTag algid, void *wincx) 1.757 +{ 1.758 + SECOidTag encAlg, hashAlg; 1.759 + SECStatus rv = sec_DecodeSigAlg(key, algid, NULL, &encAlg, &hashAlg); 1.760 + if (rv != SECSuccess) { 1.761 + return rv; 1.762 + } 1.763 + return vfy_VerifyData(buf, len, key, sig, encAlg, hashAlg, NULL, wincx); 1.764 +} 1.765 + 1.766 +SECStatus 1.767 +VFY_VerifyDataWithAlgorithmID(const unsigned char *buf, int len, 1.768 + const SECKEYPublicKey *key, 1.769 + const SECItem *sig, 1.770 + const SECAlgorithmID *sigAlgorithm, 1.771 + SECOidTag *hash, void *wincx) 1.772 +{ 1.773 + SECOidTag encAlg, hashAlg; 1.774 + SECOidTag sigAlg = SECOID_GetAlgorithmTag((SECAlgorithmID *)sigAlgorithm); 1.775 + SECStatus rv = sec_DecodeSigAlg(key, sigAlg, 1.776 + &sigAlgorithm->parameters, &encAlg, &hashAlg); 1.777 + if (rv != SECSuccess) { 1.778 + return rv; 1.779 + } 1.780 + return vfy_VerifyData(buf, len, key, sig, encAlg, hashAlg, hash, wincx); 1.781 +}