security/nss/lib/cryptohi/secsign.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

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

mercurial