Back to index

lightning-sunbird  0.9+nobinonly
secsign.c
Go to the documentation of this file.
00001 /*
00002  * Signature stuff.
00003  *
00004  * ***** BEGIN LICENSE BLOCK *****
00005  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00006  *
00007  * The contents of this file are subject to the Mozilla Public License Version
00008  * 1.1 (the "License"); you may not use this file except in compliance with
00009  * the License. You may obtain a copy of the License at
00010  * http://www.mozilla.org/MPL/
00011  *
00012  * Software distributed under the License is distributed on an "AS IS" basis,
00013  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00014  * for the specific language governing rights and limitations under the
00015  * License.
00016  *
00017  * The Original Code is the Netscape security libraries.
00018  *
00019  * The Initial Developer of the Original Code is
00020  * Netscape Communications Corporation.
00021  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00022  * the Initial Developer. All Rights Reserved.
00023  *
00024  * Contributor(s):
00025  *   Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either the GNU General Public License Version 2 or later (the "GPL"), or
00029  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00030  * in which case the provisions of the GPL or the LGPL are applicable instead
00031  * of those above. If you wish to allow use of your version of this file only
00032  * under the terms of either the GPL or the LGPL, and not to allow others to
00033  * use your version of this file under the terms of the MPL, indicate your
00034  * decision by deleting the provisions above and replace them with the notice
00035  * and other provisions required by the GPL or the LGPL. If you do not delete
00036  * the provisions above, a recipient may use your version of this file under
00037  * the terms of any one of the MPL, the GPL or the LGPL.
00038  *
00039  * ***** END LICENSE BLOCK ***** */
00040 /* $Id: secsign.c,v 1.14.2.3 2006/04/28 03:35:29 rrelyea%redhat.com Exp $ */
00041 
00042 #include <stdio.h>
00043 #include "cryptohi.h"
00044 #include "sechash.h"
00045 #include "secder.h"
00046 #include "keyhi.h"
00047 #include "secoid.h"
00048 #include "secdig.h"
00049 #include "pk11func.h"
00050 #include "secerr.h"
00051 
00052 struct SGNContextStr {
00053     SECOidTag signalg;
00054     SECOidTag hashalg;
00055     void *hashcx;
00056     const SECHashObject *hashobj;
00057     SECKEYPrivateKey *key;
00058 };
00059 
00060 SGNContext *
00061 SGN_NewContext(SECOidTag alg, SECKEYPrivateKey *key)
00062 {
00063     SGNContext *cx;
00064     SECOidTag hashalg, signalg;
00065     KeyType keyType;
00066 
00067     /* OK, map a PKCS #7 hash and encrypt algorithm into
00068      * a standard hashing algorithm. Why did we pass in the whole
00069      * PKCS #7 algTag if we were just going to change here you might
00070      * ask. Well the answer is for some cards we may have to do the
00071      * hashing on card. It may not support CKM_RSA_PKCS sign algorithm,
00072      * it may just support CKM_RSA_PKCS_WITH_SHA1 and/or CKM_RSA_PKCS_WITH_MD5.
00073      */
00074     switch (alg) {
00075       /* We probably shouldn't be generating MD2 signatures either */
00076       case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION:
00077        hashalg = SEC_OID_MD2;
00078        signalg = SEC_OID_PKCS1_RSA_ENCRYPTION;
00079        keyType = rsaKey;
00080        break;
00081       case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION:
00082         hashalg = SEC_OID_MD5;
00083        signalg = SEC_OID_PKCS1_RSA_ENCRYPTION;
00084        keyType = rsaKey;
00085        break;
00086       case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION:
00087       case SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE:
00088        hashalg = SEC_OID_SHA1;
00089        signalg = SEC_OID_PKCS1_RSA_ENCRYPTION;
00090        keyType = rsaKey;
00091        break;
00092 
00093       case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION:
00094        hashalg = SEC_OID_SHA256;
00095        signalg = SEC_OID_PKCS1_RSA_ENCRYPTION;
00096        keyType = rsaKey;
00097        break;
00098       case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION:
00099        hashalg = SEC_OID_SHA384;
00100        signalg = SEC_OID_PKCS1_RSA_ENCRYPTION;
00101        keyType = rsaKey;
00102        break;
00103       case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION:
00104        hashalg = SEC_OID_SHA512;
00105        signalg = SEC_OID_PKCS1_RSA_ENCRYPTION;
00106        keyType = rsaKey;
00107        break;
00108 
00109       /* what about normal DSA? */
00110       case SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST:
00111       case SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST:
00112        hashalg = SEC_OID_SHA1;
00113        signalg = SEC_OID_ANSIX9_DSA_SIGNATURE;
00114        keyType = dsaKey;
00115        break;
00116       case SEC_OID_MISSI_DSS:
00117       case SEC_OID_MISSI_KEA_DSS:
00118       case SEC_OID_MISSI_KEA_DSS_OLD:
00119       case SEC_OID_MISSI_DSS_OLD:
00120        hashalg = SEC_OID_SHA1;
00121        signalg = SEC_OID_MISSI_DSS; /* XXX Is there a better algid? */
00122        keyType = fortezzaKey;
00123        break;
00124       case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE:
00125        hashalg = SEC_OID_SHA1;
00126        signalg = SEC_OID_ANSIX962_EC_PUBLIC_KEY;
00127        keyType = ecKey;
00128        break;
00129       case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE:
00130        hashalg = SEC_OID_SHA256;
00131        signalg = SEC_OID_ANSIX962_EC_PUBLIC_KEY;
00132        keyType = ecKey;
00133        break;
00134       case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE:
00135        hashalg = SEC_OID_SHA384;
00136        signalg = SEC_OID_ANSIX962_EC_PUBLIC_KEY;
00137        keyType = ecKey;
00138        break;
00139       case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE:
00140        hashalg = SEC_OID_SHA512;
00141        signalg = SEC_OID_ANSIX962_EC_PUBLIC_KEY;
00142        keyType = ecKey;
00143        break;
00144       /* we don't implement MD4 hashes. 
00145        * we *CERTAINLY* don't want to sign one! */
00146       case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION:
00147       default:
00148        PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
00149        return 0;
00150     }
00151 
00152     /* verify our key type */
00153     if (key->keyType != keyType &&
00154        !((key->keyType == dsaKey) && (keyType == fortezzaKey)) &&
00155        !((key->keyType == fortezzaKey) && (keyType == dsaKey)) ) {
00156        PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
00157        return 0;
00158     }
00159 
00160 #ifndef NSS_ECC_MORE_THAN_SUITE_B
00161     if (key->keyType == ecKey) {
00162        PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
00163        return 0;
00164     }
00165 #endif
00166 
00167     cx = (SGNContext*) PORT_ZAlloc(sizeof(SGNContext));
00168     if (cx) {
00169        cx->hashalg = hashalg;
00170        cx->signalg = signalg;
00171        cx->key = key;
00172     }
00173     return cx;
00174 }
00175 
00176 void
00177 SGN_DestroyContext(SGNContext *cx, PRBool freeit)
00178 {
00179     if (cx) {
00180        if (cx->hashcx != NULL) {
00181            (*cx->hashobj->destroy)(cx->hashcx, PR_TRUE);
00182            cx->hashcx = NULL;
00183        }
00184        if (freeit) {
00185            PORT_ZFree(cx, sizeof(SGNContext));
00186        }
00187     }
00188 }
00189 
00190 SECStatus
00191 SGN_Begin(SGNContext *cx)
00192 {
00193     if (cx->hashcx != NULL) {
00194        (*cx->hashobj->destroy)(cx->hashcx, PR_TRUE);
00195        cx->hashcx = NULL;
00196     }
00197 
00198     cx->hashobj = HASH_GetHashObjectByOidTag(cx->hashalg);
00199     if (!cx->hashobj)
00200        return SECFailure;   /* error code is already set */
00201 
00202     cx->hashcx = (*cx->hashobj->create)();
00203     if (cx->hashcx == NULL)
00204        return SECFailure;
00205 
00206     (*cx->hashobj->begin)(cx->hashcx);
00207     return SECSuccess;
00208 }
00209 
00210 SECStatus
00211 SGN_Update(SGNContext *cx, unsigned char *input, unsigned inputLen)
00212 {
00213     if (cx->hashcx == NULL) {
00214        PORT_SetError(SEC_ERROR_INVALID_ARGS);
00215        return SECFailure;
00216     }
00217     (*cx->hashobj->update)(cx->hashcx, input, inputLen);
00218     return SECSuccess;
00219 }
00220 
00221 SECStatus
00222 SGN_End(SGNContext *cx, SECItem *result)
00223 {
00224     unsigned char digest[HASH_LENGTH_MAX];
00225     unsigned part1;
00226     int signatureLen;
00227     SECStatus rv;
00228     SECItem digder, sigitem;
00229     PRArenaPool *arena = 0;
00230     SECKEYPrivateKey *privKey = cx->key;
00231     SGNDigestInfo *di = 0;
00232 
00233     result->data = 0;
00234     digder.data = 0;
00235 
00236     /* Finish up digest function */
00237     if (cx->hashcx == NULL) {
00238        PORT_SetError(SEC_ERROR_INVALID_ARGS);
00239        return SECFailure;
00240     }
00241     (*cx->hashobj->end)(cx->hashcx, digest, &part1, sizeof(digest));
00242 
00243 
00244     if (privKey->keyType == rsaKey) {
00245 
00246        arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
00247        if ( !arena ) {
00248            rv = SECFailure;
00249            goto loser;
00250        }
00251     
00252        /* Construct digest info */
00253        di = SGN_CreateDigestInfo(cx->hashalg, digest, part1);
00254        if (!di) {
00255            rv = SECFailure;
00256            goto loser;
00257        }
00258 
00259        /* Der encode the digest as a DigestInfo */
00260        rv = DER_Encode(arena, &digder, SGNDigestInfoTemplate, di);
00261        if (rv != SECSuccess) {
00262            goto loser;
00263        }
00264     } else {
00265        digder.data = digest;
00266        digder.len = part1;
00267     }
00268 
00269     /*
00270     ** Encrypt signature after constructing appropriate PKCS#1 signature
00271     ** block
00272     */
00273     signatureLen = PK11_SignatureLen(privKey);
00274     if (signatureLen <= 0) {
00275        PORT_SetError(SEC_ERROR_INVALID_KEY);
00276        rv = SECFailure;
00277        goto loser;
00278     }
00279     sigitem.len = signatureLen;
00280     sigitem.data = (unsigned char*) PORT_Alloc(signatureLen);
00281 
00282     if (sigitem.data == NULL) {
00283        rv = SECFailure;
00284        goto loser;
00285     }
00286 
00287     rv = PK11_Sign(privKey, &sigitem, &digder);
00288     if (rv != SECSuccess) {
00289        PORT_Free(sigitem.data);
00290        sigitem.data = NULL;
00291        goto loser;
00292     }
00293 
00294     if ((cx->signalg == SEC_OID_ANSIX9_DSA_SIGNATURE) ||
00295         (cx->signalg == SEC_OID_ANSIX962_EC_PUBLIC_KEY)) {
00296         /* DSAU_EncodeDerSigWithLen works for DSA and ECDSA */
00297        rv = DSAU_EncodeDerSigWithLen(result, &sigitem, sigitem.len); 
00298        PORT_Free(sigitem.data);
00299        if (rv != SECSuccess)
00300            goto loser;
00301     } else {
00302        result->len = sigitem.len;
00303        result->data = sigitem.data;
00304     }
00305 
00306   loser:
00307     SGN_DestroyDigestInfo(di);
00308     if (arena != NULL) {
00309        PORT_FreeArena(arena, PR_FALSE);
00310     }
00311     return rv;
00312 }
00313 
00314 /************************************************************************/
00315 
00316 /*
00317 ** Sign a block of data returning in result a bunch of bytes that are the
00318 ** signature. Returns zero on success, an error code on failure.
00319 */
00320 SECStatus
00321 SEC_SignData(SECItem *res, unsigned char *buf, int len,
00322             SECKEYPrivateKey *pk, SECOidTag algid)
00323 {
00324     SECStatus rv;
00325     SGNContext *sgn;
00326 
00327 
00328     sgn = SGN_NewContext(algid, pk);
00329 
00330     if (sgn == NULL)
00331        return SECFailure;
00332 
00333     rv = SGN_Begin(sgn);
00334     if (rv != SECSuccess)
00335        goto loser;
00336 
00337     rv = SGN_Update(sgn, buf, len);
00338     if (rv != SECSuccess)
00339        goto loser;
00340 
00341     rv = SGN_End(sgn, res);
00342 
00343   loser:
00344     SGN_DestroyContext(sgn, PR_TRUE);
00345     return rv;
00346 }
00347 
00348 /************************************************************************/
00349     
00350 DERTemplate CERTSignedDataTemplate[] =
00351 {
00352     { DER_SEQUENCE,
00353          0, NULL, sizeof(CERTSignedData) },
00354     { DER_ANY,
00355          offsetof(CERTSignedData,data), },
00356     { DER_INLINE,
00357          offsetof(CERTSignedData,signatureAlgorithm),
00358          SECAlgorithmIDTemplate, },
00359     { DER_BIT_STRING,
00360          offsetof(CERTSignedData,signature), },
00361     { 0, }
00362 };
00363 
00364 const SEC_ASN1Template CERT_SignedDataTemplate[] =
00365 {
00366     { SEC_ASN1_SEQUENCE,
00367          0, NULL, sizeof(CERTSignedData) },
00368     { SEC_ASN1_ANY,
00369          offsetof(CERTSignedData,data), },
00370     { SEC_ASN1_INLINE,
00371          offsetof(CERTSignedData,signatureAlgorithm),
00372          SECOID_AlgorithmIDTemplate, },
00373     { SEC_ASN1_BIT_STRING,
00374          offsetof(CERTSignedData,signature), },
00375     { 0, }
00376 };
00377 
00378 SEC_ASN1_CHOOSER_IMPLEMENT(CERT_SignedDataTemplate)
00379 
00380 
00381 SECStatus
00382 SEC_DerSignData(PRArenaPool *arena, SECItem *result, 
00383        unsigned char *buf, int len, SECKEYPrivateKey *pk, SECOidTag algID)
00384 {
00385     SECItem it;
00386     CERTSignedData sd;
00387     SECStatus rv;
00388 
00389     it.data = 0;
00390 
00391     /* XXX We should probably have some asserts here to make sure the key type
00392      * and algID match
00393      */
00394 
00395     if (algID == SEC_OID_UNKNOWN) {
00396        switch(pk->keyType) {
00397          case rsaKey:
00398            algID = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION;
00399            break;
00400          case dsaKey:
00401            algID = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST;
00402            break;
00403          case ecKey:
00404            algID = SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE;
00405            break;
00406          default:
00407            PORT_SetError(SEC_ERROR_INVALID_KEY);
00408            return SECFailure;
00409        }
00410     }
00411 
00412     /* Sign input buffer */
00413     rv = SEC_SignData(&it, buf, len, pk, algID);
00414     if (rv) goto loser;
00415 
00416     /* Fill out SignedData object */
00417     PORT_Memset(&sd, 0, sizeof(sd));
00418     sd.data.data = buf;
00419     sd.data.len = len;
00420     sd.signature.data = it.data;
00421     sd.signature.len = it.len << 3;              /* convert to bit string */
00422     rv = SECOID_SetAlgorithmID(arena, &sd.signatureAlgorithm, algID, 0);
00423     if (rv) goto loser;
00424 
00425     /* DER encode the signed data object */
00426     rv = DER_Encode(arena, result, CERTSignedDataTemplate, &sd);
00427     /* FALL THROUGH */
00428 
00429   loser:
00430     PORT_Free(it.data);
00431     return rv;
00432 }
00433 
00434 SECStatus
00435 SGN_Digest(SECKEYPrivateKey *privKey,
00436               SECOidTag algtag, SECItem *result, SECItem *digest)
00437 {
00438     int modulusLen;
00439     SECStatus rv;
00440     SECItem digder;
00441     PRArenaPool *arena = 0;
00442     SGNDigestInfo *di = 0;
00443 
00444 
00445     result->data = 0;
00446 
00447     if (privKey->keyType == rsaKey) {
00448 
00449        arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
00450        if ( !arena ) {
00451            rv = SECFailure;
00452            goto loser;
00453        }
00454     
00455        /* Construct digest info */
00456        di = SGN_CreateDigestInfo(algtag, digest->data, digest->len);
00457        if (!di) {
00458            rv = SECFailure;
00459            goto loser;
00460        }
00461 
00462        /* Der encode the digest as a DigestInfo */
00463        rv = DER_Encode(arena, &digder, SGNDigestInfoTemplate, di);
00464        if (rv != SECSuccess) {
00465            goto loser;
00466        }
00467     } else {
00468        digder.data = digest->data;
00469        digder.len = digest->len;
00470     }
00471 
00472     /*
00473     ** Encrypt signature after constructing appropriate PKCS#1 signature
00474     ** block
00475     */
00476     modulusLen = PK11_SignatureLen(privKey);
00477     if (modulusLen <= 0) {
00478        PORT_SetError(SEC_ERROR_INVALID_KEY);
00479        rv = SECFailure;
00480        goto loser;
00481     }
00482     result->len = modulusLen;
00483     result->data = (unsigned char*) PORT_Alloc(modulusLen);
00484 
00485     if (result->data == NULL) {
00486        rv = SECFailure;
00487        goto loser;
00488     }
00489 
00490     rv = PK11_Sign(privKey, result, &digder);
00491     if (rv != SECSuccess) {
00492        PORT_Free(result->data);
00493        result->data = NULL;
00494     }
00495 
00496   loser:
00497     SGN_DestroyDigestInfo(di);
00498     if (arena != NULL) {
00499        PORT_FreeArena(arena, PR_FALSE);
00500     }
00501     return rv;
00502 }
00503 
00504 SECOidTag
00505 SEC_GetSignatureAlgorithmOidTag(KeyType keyType, SECOidTag hashAlgTag)
00506 {
00507     SECOidTag sigTag = SEC_OID_UNKNOWN;
00508 
00509     switch (keyType) {
00510     case rsaKey:
00511        switch (hashAlgTag) {
00512        case SEC_OID_MD2:
00513            sigTag = SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION;     break;
00514        case SEC_OID_UNKNOWN:       /* default for RSA if not specified */
00515        case SEC_OID_MD5:
00516            sigTag = SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION;     break;
00517        case SEC_OID_SHA1:
00518            sigTag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION;    break;
00519        case SEC_OID_SHA256:
00520            sigTag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION;  break;
00521        case SEC_OID_SHA384:
00522            sigTag = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION;  break;
00523        case SEC_OID_SHA512:
00524            sigTag = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION;  break;
00525        default:
00526            break;
00527        }
00528        break;
00529     case dsaKey:
00530        switch (hashAlgTag) {
00531        case SEC_OID_UNKNOWN:       /* default for DSA if not specified */
00532        case SEC_OID_SHA1:
00533            sigTag = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST; break;
00534        default:
00535            break;
00536        }
00537        break;
00538     case ecKey:
00539        switch (hashAlgTag) {
00540        case SEC_OID_UNKNOWN:       /* default for ECDSA if hash not specified */
00541        case SEC_OID_SHA1:      /*  is ECDSA_SHA1_SIGNTARURE */
00542            sigTag = SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE; break;
00543        case SEC_OID_SHA256:
00544            sigTag = SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE; break;
00545        case SEC_OID_SHA384:
00546            sigTag = SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE; break;
00547        case SEC_OID_SHA512:
00548            sigTag = SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE; break;
00549        default:
00550            break;
00551        }
00552        break;
00553     default:
00554        break;
00555     }
00556     return sigTag;
00557 }