security/nss/lib/cryptohi/secvfy.c

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

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

mercurial