security/nss/lib/cryptohi/secvfy.c

changeset 0
6474c204b198
     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 +}

mercurial