diff options
author | relyea%netscape.com <devnull@localhost> | 2000-03-31 20:13:40 +0000 |
---|---|---|
committer | relyea%netscape.com <devnull@localhost> | 2000-03-31 20:13:40 +0000 |
commit | 9502869e82d4f3ce26b292263e1c626dca3a34f3 (patch) | |
tree | 4d0f8ab157505b57c13a5e2bdf979560ab751527 /security/nss/lib/cryptohi | |
parent | 222a52dab759085f56dcb6588b69a6a937d82aa2 (diff) | |
download | nss-hg-9502869e82d4f3ce26b292263e1c626dca3a34f3.tar.gz |
Initial NSS Open Source checkin
Diffstat (limited to 'security/nss/lib/cryptohi')
-rw-r--r-- | security/nss/lib/cryptohi/Makefile | 77 | ||||
-rw-r--r-- | security/nss/lib/cryptohi/config.mk | 44 | ||||
-rw-r--r-- | security/nss/lib/cryptohi/cryptohi.h | 236 | ||||
-rw-r--r-- | security/nss/lib/cryptohi/cryptoht.h | 45 | ||||
-rw-r--r-- | security/nss/lib/cryptohi/dsautil.c | 229 | ||||
-rw-r--r-- | security/nss/lib/cryptohi/hasht.h | 87 | ||||
-rw-r--r-- | security/nss/lib/cryptohi/key.h | 44 | ||||
-rw-r--r-- | security/nss/lib/cryptohi/keyhi.h | 211 | ||||
-rw-r--r-- | security/nss/lib/cryptohi/keyt.h | 46 | ||||
-rw-r--r-- | security/nss/lib/cryptohi/keythi.h | 83 | ||||
-rw-r--r-- | security/nss/lib/cryptohi/manifest.mn | 64 | ||||
-rw-r--r-- | security/nss/lib/cryptohi/sechash.c | 274 | ||||
-rw-r--r-- | security/nss/lib/cryptohi/sechash.h | 77 | ||||
-rw-r--r-- | security/nss/lib/cryptohi/seckey.c | 1649 | ||||
-rw-r--r-- | security/nss/lib/cryptohi/secsign.c | 497 | ||||
-rw-r--r-- | security/nss/lib/cryptohi/secvfy.c | 389 |
16 files changed, 4052 insertions, 0 deletions
diff --git a/security/nss/lib/cryptohi/Makefile b/security/nss/lib/cryptohi/Makefile new file mode 100644 index 000000000..ced902117 --- /dev/null +++ b/security/nss/lib/cryptohi/Makefile @@ -0,0 +1,77 @@ +#! gmake +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is the Netscape security libraries. +# +# The Initial Developer of the Original Code is Netscape +# Communications Corporation. Portions created by Netscape are +# Copyright (C) 1994-2000 Netscape Communications Corporation. All +# Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the +# terms of the GNU General Public License Version 2 or later (the +# "GPL"), in which case the provisions of the GPL are applicable +# instead of those above. If you wish to allow use of your +# version of this file only under the terms of the GPL and not to +# allow others to use your version of this file under the MPL, +# indicate your decision by deleting the provisions above and +# replace them with the notice and other provisions required by +# the GPL. If you do not delete the provisions above, a recipient +# may use your version of this file under either the MPL or the +# GPL. +# + +####################################################################### +# (1) Include initial platform-independent assignments (MANDATORY). # +####################################################################### + +include manifest.mn + +####################################################################### +# (2) Include "global" configuration information. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +-include config.mk + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + + +export:: private_export + diff --git a/security/nss/lib/cryptohi/config.mk b/security/nss/lib/cryptohi/config.mk new file mode 100644 index 000000000..a73a1086e --- /dev/null +++ b/security/nss/lib/cryptohi/config.mk @@ -0,0 +1,44 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is the Netscape security libraries. +# +# The Initial Developer of the Original Code is Netscape +# Communications Corporation. Portions created by Netscape are +# Copyright (C) 1994-2000 Netscape Communications Corporation. All +# Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the +# terms of the GNU General Public License Version 2 or later (the +# "GPL"), in which case the provisions of the GPL are applicable +# instead of those above. If you wish to allow use of your +# version of this file only under the terms of the GPL and not to +# allow others to use your version of this file under the MPL, +# indicate your decision by deleting the provisions above and +# replace them with the notice and other provisions required by +# the GPL. If you do not delete the provisions above, a recipient +# may use your version of this file under either the MPL or the +# GPL. +# + +# +# Override TARGETS variable so that only static libraries +# are specifed as dependencies within rules.mk. +# + +TARGETS = $(LIBRARY) +SHARED_LIBRARY = +IMPORT_LIBRARY = +PURE_LIBRARY = +PROGRAM = + diff --git a/security/nss/lib/cryptohi/cryptohi.h b/security/nss/lib/cryptohi/cryptohi.h new file mode 100644 index 000000000..07d8057c7 --- /dev/null +++ b/security/nss/lib/cryptohi/cryptohi.h @@ -0,0 +1,236 @@ +/* + * crypto.h - public data structures and prototypes for the crypto library + * + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + * + * $Id$ + */ + +#ifndef _CRYPTOHI_H_ +#define _CRYPTOHI_H_ + +#include "blapi.h" + +#include "mcom_db.h" + +#include "seccomon.h" +#include "secrngt.h" +#include "secoidt.h" +#include "secdert.h" +#include "cryptoht.h" +#include "keyt.h" +#include "certt.h" + + +SEC_BEGIN_PROTOS + + +/****************************************/ +/* +** DER encode/decode DSA signatures +*/ + +/* ANSI X9.57 defines DSA signatures as DER encoded data. Our DSA code (and + * most of the rest of the world) just generates 40 bytes of raw data. These + * functions convert between formats. + */ +extern SECStatus DSAU_EncodeDerSig(SECItem *dest, SECItem *src); +extern SECItem *DSAU_DecodeDerSig(SECItem *item); + + + +/****************************************/ +/* +** Signature creation operations +*/ + +/* +** Create a new signature context used for signing a data stream. +** "alg" the signature algorithm to use (e.g. SEC_OID_RSA_WITH_MD5) +** "privKey" the private key to use +*/ +extern SGNContext *SGN_NewContext(SECOidTag alg, SECKEYPrivateKey *privKey); + +/* +** Destroy a signature-context object +** "key" the object +** "freeit" if PR_TRUE then free the object as well as its sub-objects +*/ +extern void SGN_DestroyContext(SGNContext *cx, PRBool freeit); + +/* +** Reset the signing context "cx" to its initial state, preparing it for +** another stream of data. +*/ +extern SECStatus SGN_Begin(SGNContext *cx); + +/* +** Update the signing context with more data to sign. +** "cx" the context +** "input" the input data to sign +** "inputLen" the length of the input data +*/ +extern SECStatus SGN_Update(SGNContext *cx, unsigned char *input, + unsigned int inputLen); + +/* +** Finish the signature process. Use either k0 or k1 to sign the data +** stream that was input using SGN_Update. The resulting signature is +** formatted using PKCS#1 and then encrypted using RSA private or public +** encryption. +** "cx" the context +** "result" the final signature data (memory is allocated) +*/ +extern SECStatus SGN_End(SGNContext *cx, SECItem *result); + +/* +** Sign a single block of data using private key encryption and given +** signature/hash algorithm. +** "result" the final signature data (memory is allocated) +** "buf" the input data to sign +** "len" the amount of data to sign +** "pk" the private key to encrypt with +** "algid" the signature/hash algorithm to sign with +** (must be compatible with the key type). +*/ +extern SECStatus SEC_SignData(SECItem *result, unsigned char *buf, int len, + SECKEYPrivateKey *pk, SECOidTag algid); + +/* +** Sign a pre-digested block of data using private key encryption, encoding +** The given signature/hash algorithm. +** "result" the final signature data (memory is allocated) +** "digest" the digest to sign +** "pk" the private key to encrypt with +** "algtag" The algorithm tag to encode (need for RSA only) +*/ +extern SECStatus SGN_Digest(SECKEYPrivateKey *privKey, + SECOidTag algtag, SECItem *result, SECItem *digest); + +/* +** DER sign a single block of data using private key encryption and the +** MD5 hashing algorithm. This routine first computes a digital signature +** using SEC_SignData, then wraps it with an CERTSignedData and then der +** encodes the result. +** "arena" is the memory arena to use to allocate data from +** "result" the final der encoded data (memory is allocated) +** "buf" the input data to sign +** "len" the amount of data to sign +** "pk" the private key to encrypt with +*/ +extern SECStatus SEC_DerSignData(PRArenaPool *arena, SECItem *result, + unsigned char *buf, int len, + SECKEYPrivateKey *pk, SECOidTag algid); + +/* +** Destroy a signed-data object. +** "sd" the object +** "freeit" if PR_TRUE then free the object as well as its sub-objects +*/ +extern void SEC_DestroySignedData(CERTSignedData *sd, PRBool freeit); + +/****************************************/ +/* +** Signature verification operations +*/ + +/* +** Create a signature verification context. +** "key" the public key to verify with +** "sig" the encrypted signature data +** "algid" specifies the signing algorithm to use. This must match +** the key type. +** "wincx" void pointer to the window context +*/ +extern VFYContext *VFY_CreateContext(SECKEYPublicKey *key, SECItem *sig, + SECOidTag algid, void *wincx); + +/* +** Destroy a verification-context object. +** "cx" the context to destroy +** "freeit" if PR_TRUE then free the object as well as its sub-objects +*/ +extern void VFY_DestroyContext(VFYContext *cx, PRBool freeit); + +extern SECStatus VFY_Begin(VFYContext *cx); + +/* +** Update a verification context with more input data. The input data +** is fed to a secure hash function (depending on what was in the +** encrypted signature data). +** "cx" the context +** "input" the input data +** "inputLen" the amount of input data +*/ +extern SECStatus VFY_Update(VFYContext *cx, unsigned char *input, + unsigned int inputLen); + +/* +** Finish the verification process. The return value is a status which +** indicates success or failure. On success, the SECSuccess value is +** returned. Otherwise, SECFailure is returned and the error code found +** using PORT_GetError() indicates what failure occurred. +** "cx" the context +*/ +extern SECStatus VFY_End(VFYContext *cx); + +/* +** Verify the signature on a block of data for which we already have +** the digest. The signature data is an RSA private key encrypted +** block of data formatted according to PKCS#1. +** "dig" the digest +** "key" the public key to check the signature with +** "sig" the encrypted signature data +** "algid" specifies the signing algorithm to use. This must match +** the key type. +**/ +extern SECStatus VFY_VerifyDigest(SECItem *dig, SECKEYPublicKey *key, + SECItem *sig, SECOidTag algid, void *wincx); + +/* +** Verify the signature on a block of data. The signature data is an RSA +** private key encrypted block of data formatted according to PKCS#1. +** "buf" the input data +** "len" the length of the input data +** "key" the public key to check the signature with +** "sig" the encrypted signature data +** "algid" specifies the signing algorithm to use. This must match +** the key type. +*/ +extern SECStatus VFY_VerifyData(unsigned char *buf, int len, + SECKEYPublicKey *key, SECItem *sig, + SECOidTag algid, void *wincx); + + +SEC_END_PROTOS + +#endif /* _CRYPTOHI_H_ */ diff --git a/security/nss/lib/cryptohi/cryptoht.h b/security/nss/lib/cryptohi/cryptoht.h new file mode 100644 index 000000000..3116db279 --- /dev/null +++ b/security/nss/lib/cryptohi/cryptoht.h @@ -0,0 +1,45 @@ +/* + * cryptoht.h - public data structures for the crypto library + * + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + * + * $Id$ + */ + +#ifndef _CRYPTOHT_H_ +#define _CRYPTOHT_H_ + +typedef struct SGNContextStr SGNContext; +typedef struct VFYContextStr VFYContext; + + +#endif /* _CRYPTOHT_H_ */ diff --git a/security/nss/lib/cryptohi/dsautil.c b/security/nss/lib/cryptohi/dsautil.c new file mode 100644 index 000000000..ed6f9cec8 --- /dev/null +++ b/security/nss/lib/cryptohi/dsautil.c @@ -0,0 +1,229 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ +#include "secasn1.h" +#include "secitem.h" +#include "prerr.h" + +#ifndef DSA_SUBPRIME_LEN +#define DSA_SUBPRIME_LEN 20 /* bytes */ +#endif + +typedef struct { + SECItem r; + SECItem s; +} DSA_ASN1Signature; + +const SEC_ASN1Template DSA_SignatureTemplate[] = +{ + { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(DSA_ASN1Signature) }, + { SEC_ASN1_INTEGER, offsetof(DSA_ASN1Signature,r) }, + { SEC_ASN1_INTEGER, offsetof(DSA_ASN1Signature,s) }, + { 0, } +}; + +/* Input is variable length multi-byte integer, MSB first (big endian). +** Most signficant bit of first byte is NOT treated as a sign bit. +** May be one or more leading bytes of zeros. +** Output is variable length multi-byte integer, MSB first (big endian). +** Most significant bit of first byte will be zero (positive sign bit) +** No more than one leading zero byte. +** Caller supplies dest buffer, and assures that it is long enough, +** e.g. at least one byte longer that src's buffer. +*/ +void +DSAU_ConvertUnsignedToSigned(SECItem *dest, SECItem *src) +{ + unsigned char *pSrc = src->data; + unsigned char *pDst = dest->data; + unsigned int cntSrc = src->len; + unsigned int cntDst = dest->len; + unsigned char c; + + /* skip any leading zeros. */ + while (cntSrc && !(c = *pSrc)) { + pSrc++; + cntSrc--; + } + if (!cntSrc) { + *pDst = 0; + dest->len = 1; + return; + } + + if (c & 0x80) + *pDst++ = 0; + + PORT_Memcpy(pDst, pSrc, cntSrc); + dest->len = (pDst - dest->data) + cntSrc; +} + +/* +** src is a buffer holding a signed variable length integer. +** dest is a buffer which will be filled with an unsigned integer, +** MSB first (big endian) with leading zeros, so that the last byte +** of src will be the LSB of the integer. The result will be exactly +** the length specified by the caller in dest->len. +** src can be shorter than dest. src can be longer than dst, but only +** if the extra leading bytes are zeros. +*/ +SECStatus +DSAU_ConvertSignedToFixedUnsigned(SECItem *dest, SECItem *src) +{ + unsigned char *pSrc = src->data; + unsigned char *pDst = dest->data; + unsigned int cntSrc = src->len; + unsigned int cntDst = dest->len; + int zCount = cntDst - cntSrc; + + if (zCount > 0) { + PORT_Memset(pDst, 0, zCount); + PORT_Memcpy(pDst + zCount, pSrc, cntSrc); + return SECSuccess; + } + if (zCount <= 0) { + /* Source is longer than destination. Check for leading zeros. */ + while (zCount++ < 0) { + if (*pSrc++ != 0) + goto loser; + } + } + PORT_Memcpy(pDst, pSrc, cntDst); + return SECSuccess; + +loser: + PORT_SetError( PR_INVALID_ARGUMENT_ERROR ); + return SECFailure; +} + +/* src is a "raw" DSA signature, 20 bytes of r followed by 20 bytes of s. +** dest is the signature DER encoded. ? +*/ +SECStatus +DSAU_EncodeDerSig(SECItem *dest, SECItem *src) +{ + SECItem * item; + SECItem srcItem; + DSA_ASN1Signature sig; + unsigned char signedR[DSA_SUBPRIME_LEN + 1]; + unsigned char signedS[DSA_SUBPRIME_LEN + 1]; + + PORT_Memset(&sig, 0, sizeof(sig)); + + PORT_Assert(src->len == 2 * DSA_SUBPRIME_LEN); + if (src->len != 2 * DSA_SUBPRIME_LEN) { + PORT_SetError( PR_INVALID_ARGUMENT_ERROR ); + return SECFailure; + } + + /* Must convert r and s from "unsigned" integers to "signed" integers. + ** If the high order bit of the first byte (MSB) is 1, then must + ** prepend with leading zero. + ** Must remove all but one leading zero byte from numbers. + */ + sig.r.data = signedR; + sig.r.len = sizeof signedR; + sig.s.data = signedS; + sig.s.len = sizeof signedR; + + srcItem.data = src->data; + srcItem.len = DSA_SUBPRIME_LEN; + + DSAU_ConvertUnsignedToSigned(&sig.r, &srcItem); + srcItem.data += DSA_SUBPRIME_LEN; + DSAU_ConvertUnsignedToSigned(&sig.s, &srcItem); + + item = SEC_ASN1EncodeItem(NULL, dest, &sig, DSA_SignatureTemplate); + if (item == NULL) + return SECFailure; + + /* XXX leak item? */ + return SECSuccess; +} + +/* src is a DER-encoded DSA signature. +** Returns a newly-allocated SECItem structure, pointing at a newly allocated +** buffer containing the "raw" DSA signature, which is 20 bytes of r, +** followed by 20 bytes of s. +*/ +SECItem * +DSAU_DecodeDerSig(SECItem *item) +{ + SECItem * result = NULL; + SECStatus status; + DSA_ASN1Signature sig; + SECItem dst; + + PORT_Memset(&sig, 0, sizeof(sig)); + + result = PORT_ZNew(SECItem); + if (result == NULL) + goto loser; + + result->len = 2 * DSA_SUBPRIME_LEN; + result->data = (unsigned char*)PORT_Alloc(2 * DSA_SUBPRIME_LEN); + if (result->data == NULL) + goto loser; + + status = SEC_ASN1DecodeItem(NULL, &sig, DSA_SignatureTemplate, item); + if (status != SECSuccess) + goto loser; + + /* Convert sig.r and sig.s from variable length signed integers to + ** fixed length unsigned integers. + */ + dst.data = result->data; + dst.len = DSA_SUBPRIME_LEN; + status = DSAU_ConvertSignedToFixedUnsigned(&dst, &sig.r); + if (status != SECSuccess) + goto loser; + + dst.data += DSA_SUBPRIME_LEN; + status = DSAU_ConvertSignedToFixedUnsigned(&dst, &sig.s); + if (status != SECSuccess) + goto loser; + +done: + if (sig.r.data != NULL) + PORT_Free(sig.r.data); + if (sig.s.data != NULL) + PORT_Free(sig.s.data); + + return result; + +loser: + if (result != NULL) { + SECITEM_FreeItem(result, PR_TRUE); + result = NULL; + } + goto done; +} diff --git a/security/nss/lib/cryptohi/hasht.h b/security/nss/lib/cryptohi/hasht.h new file mode 100644 index 000000000..697520015 --- /dev/null +++ b/security/nss/lib/cryptohi/hasht.h @@ -0,0 +1,87 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + * + * hasht.h - public data structures for the hashing library + * + * $Id$ + */ + +#ifndef _HASHT_H_ +#define _HASHT_H_ + +/* Opaque objects */ +typedef struct SECHashObjectStr SECHashObject; +typedef struct HASHContextStr HASHContext; + +/* + * The hash functions the security library supports + * NOTE the order must match the definition of SECHashObjects[]! + */ +typedef enum { + HASH_AlgNULL, + HASH_AlgMD2, + HASH_AlgMD5, + HASH_AlgSHA1, + HASH_AlgTOTAL +} HASH_HashType; + +/* + * Number of bytes each hash algorithm produces + */ +#define MD2_LENGTH 16 +#define MD5_LENGTH 16 +#define SHA1_LENGTH 20 + +/* + * Structure to hold hash computation info and routines + */ +struct SECHashObjectStr { + unsigned int length; + void * (*create)(void); + void * (*clone)(void *); + void (*destroy)(void *, PRBool); + void (*begin)(void *); + void (*update)(void *, const unsigned char *, unsigned int); + void (*end)(void *, unsigned char *, unsigned int *, unsigned int); +}; + +struct HASHContextStr { + struct SECHashObjectStr *hashobj; + void *hash_context; +}; + +extern SECHashObject SECHashObjects[]; + +/*only those functions below the PKCS #11 line should use SECRawHashObjects*/ +extern SECHashObject SECRawHashObjects[]; + +#endif /* _HASHT_H_ */ diff --git a/security/nss/lib/cryptohi/key.h b/security/nss/lib/cryptohi/key.h new file mode 100644 index 000000000..7e68cdb58 --- /dev/null +++ b/security/nss/lib/cryptohi/key.h @@ -0,0 +1,44 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + * + * key.h - public data structures and prototypes for the private key library + * + * $Id$ + */ + +#ifndef _KEY_H_ +#define _KEY_H_ + +#include "keyhi.h" +#include "keylow.h" + +#endif /* _KEY_H_ */ diff --git a/security/nss/lib/cryptohi/keyhi.h b/security/nss/lib/cryptohi/keyhi.h new file mode 100644 index 000000000..6c1a70546 --- /dev/null +++ b/security/nss/lib/cryptohi/keyhi.h @@ -0,0 +1,211 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + * + * key.h - public data structures and prototypes for the private key library + * + * $Id$ + */ + +#ifndef _KEYHI_H_ +#define _KEYHI_H_ + +#include "plarena.h" + +#include "seccomon.h" +#include "secoidt.h" +#include "secdert.h" +#include "keythi.h" +#include "certt.h" +#include "secpkcs5.h" + +SEC_BEGIN_PROTOS + + +/* +** Destroy a subject-public-key-info object. +*/ +extern void SECKEY_DestroySubjectPublicKeyInfo(CERTSubjectPublicKeyInfo *spki); + +/* +** Copy subject-public-key-info "src" to "dst". "dst" is filled in +** appropriately (memory is allocated for each of the sub objects). +*/ +extern SECStatus SECKEY_CopySubjectPublicKeyInfo(PRArenaPool *arena, + CERTSubjectPublicKeyInfo *dst, + CERTSubjectPublicKeyInfo *src); + +/* +** Update the PQG parameters for a cert's public key. +** Only done for DSA and Fortezza certs +*/ +extern SECStatus +SECKEY_UpdateCertPQG(CERTCertificate * subjectCert); + + +/* Compare the KEA parameters of two public keys. + * Only used by fortezza. */ + +extern SECStatus +SECKEY_KEAParamCompare(CERTCertificate *cert1,CERTCertificate *cert2); + +/* +** Return the strength of the public key +*/ +extern unsigned SECKEY_PublicKeyStrength(SECKEYPublicKey *pubk); + + +/* +** Make a copy of the private key "privKey" +*/ +extern SECKEYPrivateKey *SECKEY_CopyPrivateKey(SECKEYPrivateKey *privKey); + +/* +** Make a copy of the public key "pubKey" +*/ +extern SECKEYPublicKey *SECKEY_CopyPublicKey(SECKEYPublicKey *pubKey); + +/* +** Convert a private key "privateKey" into a public key +*/ +extern SECKEYPublicKey *SECKEY_ConvertToPublicKey(SECKEYPrivateKey *privateKey); + +/* + * create a new RSA key pair. The public Key is returned... + */ +SECKEYPrivateKey *SECKEY_CreateRSAPrivateKey(int keySizeInBits, + SECKEYPublicKey **pubk, void *cx); +/* +** Create a subject-public-key-info based on a public key. +*/ +extern CERTSubjectPublicKeyInfo * +SECKEY_CreateSubjectPublicKeyInfo(SECKEYPublicKey *k); + +/* +** Decode a DER encoded public key into an SECKEYPublicKey structure. +*/ +extern SECKEYPublicKey *SECKEY_DecodeDERPublicKey(SECItem *pubkder); + +/* +** Convert a base64 ascii encoded DER public key to our internal format. +*/ +extern SECKEYPublicKey *SECKEY_ConvertAndDecodePublicKey(char *pubkstr); + +/* +** Convert a base64 ascii encoded DER public key and challenge to spki, +** and verify the signature and challenge data are correct +*/ +extern CERTSubjectPublicKeyInfo * +SECKEY_ConvertAndDecodePublicKeyAndChallenge(char *pkacstr, char *challenge, + void *cx); + +/* +** Decode a DER encoded subject public key info into a +** CERTSubjectPublicKeyInfo structure. +*/ +extern CERTSubjectPublicKeyInfo * +SECKEY_DecodeDERSubjectPublicKeyInfo(SECItem *spkider); + +/* +** Convert a base64 ascii encoded DER subject public key info to our +** internal format. +*/ +extern CERTSubjectPublicKeyInfo * +SECKEY_ConvertAndDecodeSubjectPublicKeyInfo(char *spkistr); + +/* +** Destroy a private key object. +** "key" the object +*/ +extern void SECKEY_DestroyPrivateKey(SECKEYPrivateKey *key); + +/* +** Destroy a public key object. +** "key" the object +*/ +extern void SECKEY_DestroyPublicKey(SECKEYPublicKey *key); + +/* Destroy and zero out a private key info structure. for now this + * function zero's out memory allocated in an arena for the key + * since PORT_FreeArena does not currently do this. + * + * NOTE -- If a private key info is allocated in an arena, one should + * not call this function with freeit = PR_FALSE. The function should + * destroy the arena. + */ +extern void +SECKEY_DestroyPrivateKeyInfo(SECKEYPrivateKeyInfo *pvk, PRBool freeit); + +/* Destroy and zero out an encrypted private key info. + * + * NOTE -- If a encrypted private key info is allocated in an arena, one should + * not call this function with freeit = PR_FALSE. The function should + * destroy the arena. + */ +extern void +SECKEY_DestroyEncryptedPrivateKeyInfo(SECKEYEncryptedPrivateKeyInfo *epki, + PRBool freeit); + +/* Copy private key info structure. + * poolp is the arena into which the contents of from is to be copied. + * NULL is a valid entry. + * to is the destination private key info + * from is the source private key info + * if either from or to is NULL or an error occurs, SECFailure is + * returned. otherwise, SECSuccess is returned. + */ +extern SECStatus +SECKEY_CopyPrivateKeyInfo(PRArenaPool *poolp, + SECKEYPrivateKeyInfo *to, + SECKEYPrivateKeyInfo *from); + +/* Copy encrypted private key info structure. + * poolp is the arena into which the contents of from is to be copied. + * NULL is a valid entry. + * to is the destination encrypted private key info + * from is the source encrypted private key info + * if either from or to is NULL or an error occurs, SECFailure is + * returned. otherwise, SECSuccess is returned. + */ +extern SECStatus +SECKEY_CopyEncryptedPrivateKeyInfo(PRArenaPool *poolp, + SECKEYEncryptedPrivateKeyInfo *to, + SECKEYEncryptedPrivateKeyInfo *from); +/* + * Accessor functions for key type of public and private keys. + */ +KeyType SECKEY_GetPrivateKeyType(SECKEYPrivateKey *privKey); +KeyType SECKEY_GetPublicKeyType(SECKEYPublicKey *pubKey); + + +SEC_END_PROTOS + +#endif /* _KEYHI_H_ */ diff --git a/security/nss/lib/cryptohi/keyt.h b/security/nss/lib/cryptohi/keyt.h new file mode 100644 index 000000000..f102c8a26 --- /dev/null +++ b/security/nss/lib/cryptohi/keyt.h @@ -0,0 +1,46 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + * + * keyt.h - public data structures for the private key library + * + * $Id$ + */ + +#ifndef _KEYT_H_ +#define _KEYT_H_ + +#include "keytlow.h" +#include "keytboth.h" +#include "keythi.h" +#include "keydbt.h" + +#endif /* _KEYT_H_ */ diff --git a/security/nss/lib/cryptohi/keythi.h b/security/nss/lib/cryptohi/keythi.h new file mode 100644 index 000000000..ba1aec401 --- /dev/null +++ b/security/nss/lib/cryptohi/keythi.h @@ -0,0 +1,83 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ +#ifndef _KEYTHI_H_ +#define _KEYTHI_H_ 1 + +#include "keytlow.h" +#include "keytboth.h" +#include "plarena.h" +#include "pkcs11t.h" +#include "secmodt.h" + +/* +** A Generic public key object. +*/ +struct SECKEYPublicKeyStr { + PLArenaPool *arena; + KeyType keyType; + PK11SlotInfo *pkcs11Slot; + CK_OBJECT_HANDLE pkcs11ID; + union { + RSAPublicKey rsa; + DSAPublicKey dsa; + DHPublicKey dh; + KEAPublicKey kea; + FortezzaPublicKey fortezza; + } u; +}; +typedef struct SECKEYPublicKeyStr SECKEYPublicKey; + +/* +** A generic key structure +*/ +struct SECKEYPrivateKeyStr { + PLArenaPool *arena; + KeyType keyType; + PK11SlotInfo *pkcs11Slot; /* pkcs11 slot this key lives in */ + CK_OBJECT_HANDLE pkcs11ID; /* ID of pkcs11 object */ + PRBool pkcs11IsTemp; /* temp pkcs11 object, delete it when done */ + void *wincx; /* context for errors and pw prompts */ +}; +typedef struct SECKEYPrivateKeyStr SECKEYPrivateKey; + +/* Despite the name, this struct isn't used by any pkcs5 code. +** It's used by pkcs7 and pkcs12 code. +*/ +typedef struct { + SECItem *pwitem; + PK11SymKey *key; + PK11SlotInfo *slot; + void *wincx; +} SEC_PKCS5KeyAndPassword; + +#endif /* _KEYTHI_H_ */ diff --git a/security/nss/lib/cryptohi/manifest.mn b/security/nss/lib/cryptohi/manifest.mn new file mode 100644 index 000000000..a4a76a7df --- /dev/null +++ b/security/nss/lib/cryptohi/manifest.mn @@ -0,0 +1,64 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is the Netscape security libraries. +# +# The Initial Developer of the Original Code is Netscape +# Communications Corporation. Portions created by Netscape are +# Copyright (C) 1994-2000 Netscape Communications Corporation. All +# Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the +# terms of the GNU General Public License Version 2 or later (the +# "GPL"), in which case the provisions of the GPL are applicable +# instead of those above. If you wish to allow use of your +# version of this file only under the terms of the GPL and not to +# allow others to use your version of this file under the MPL, +# indicate your decision by deleting the provisions above and +# replace them with the notice and other provisions required by +# the GPL. If you do not delete the provisions above, a recipient +# may use your version of this file under either the MPL or the +# GPL. +# +CORE_DEPTH = ../../.. + +MODULE = security + +REQUIRES = dbm + +LIBRARY_NAME = cryptohi + +EXPORTS = \ + cryptohi.h \ + cryptoht.h \ + hasht.h \ + key.h \ + keyhi.h \ + keyt.h \ + keythi.h \ + sechash.h \ + $(NULL) + +PRIVATE_EXPORTS = \ + $(NULL) + +LIBSRCS = \ + sechash.c \ + seckey.c \ + secsign.c \ + secvfy.c \ + dsautil.c \ + $(NULL) + +CSRCS = $(LIBSRCS) + diff --git a/security/nss/lib/cryptohi/sechash.c b/security/nss/lib/cryptohi/sechash.c new file mode 100644 index 000000000..94000f543 --- /dev/null +++ b/security/nss/lib/cryptohi/sechash.c @@ -0,0 +1,274 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ +#include "sechash.h" +#include "secoidt.h" +#include "blapi.h" +#include "pk11func.h" /* for the PK11_ calls below. */ + +static void * +null_hash_new_context(void) +{ + return NULL; +} + +static void * +null_hash_clone_context(void *v) +{ + PORT_Assert(v == NULL); + return NULL; +} + +static void +null_hash_begin(void *v) +{ +} + +static void +null_hash_update(void *v, const unsigned char *input, unsigned int length) +{ +} + +static void +null_hash_end(void *v, unsigned char *output, unsigned int *outLen, + unsigned int maxOut) +{ + *outLen = 0; +} + +static void +null_hash_destroy_context(void *v, PRBool b) +{ + PORT_Assert(v == NULL); +} + + +static void * +md2_NewContext(void) { + return (void *) PK11_CreateDigestContext(SEC_OID_MD2); +} + +static void * +md5_NewContext(void) { + return (void *) PK11_CreateDigestContext(SEC_OID_MD5); +} + +static void * +sha1_NewContext(void) { + return (void *) PK11_CreateDigestContext(SEC_OID_SHA1); +} + +SECHashObject SECHashObjects[] = { + { 0, + (void * (*)(void)) null_hash_new_context, + (void * (*)(void *)) null_hash_clone_context, + (void (*)(void *, PRBool)) null_hash_destroy_context, + (void (*)(void *)) null_hash_begin, + (void (*)(void *, const unsigned char *, unsigned int)) null_hash_update, + (void (*)(void *, unsigned char *, unsigned int *, + unsigned int)) null_hash_end + }, + { MD2_LENGTH, + (void * (*)(void)) md2_NewContext, + (void * (*)(void *)) PK11_CloneContext, + (void (*)(void *, PRBool)) PK11_DestroyContext, + (void (*)(void *)) PK11_DigestBegin, + (void (*)(void *, const unsigned char *, unsigned int)) PK11_DigestOp, + (void (*)(void *, unsigned char *, unsigned int *, unsigned int)) + PK11_DigestFinal + }, + { MD5_LENGTH, + (void * (*)(void)) md5_NewContext, + (void * (*)(void *)) PK11_CloneContext, + (void (*)(void *, PRBool)) PK11_DestroyContext, + (void (*)(void *)) PK11_DigestBegin, + (void (*)(void *, const unsigned char *, unsigned int)) PK11_DigestOp, + (void (*)(void *, unsigned char *, unsigned int *, unsigned int)) + PK11_DigestFinal + }, + { SHA1_LENGTH, + (void * (*)(void)) sha1_NewContext, + (void * (*)(void *)) PK11_CloneContext, + (void (*)(void *, PRBool)) PK11_DestroyContext, + (void (*)(void *)) PK11_DigestBegin, + (void (*)(void *, const unsigned char *, unsigned int)) PK11_DigestOp, + (void (*)(void *, unsigned char *, unsigned int *, unsigned int)) + PK11_DigestFinal + }, +}; + +unsigned int +HASH_ResultLen(HASH_HashType type) +{ + if ( ( type < HASH_AlgNULL ) || ( type >= HASH_AlgTOTAL ) ) { + return(0); + } + + return(SECHashObjects[type].length); +} + +unsigned int +HASH_ResultLenContext(HASHContext *context) +{ + return(context->hashobj->length); +} + + + +SECStatus +HASH_HashBuf(HASH_HashType type, + unsigned char *dest, + unsigned char *src, + uint32 src_len) +{ + HASHContext *cx; + unsigned int part; + + if ( ( type < HASH_AlgNULL ) || ( type >= HASH_AlgTOTAL ) ) { + return(SECFailure); + } + + cx = HASH_Create(type); + if ( cx == NULL ) { + return(SECFailure); + } + HASH_Begin(cx); + HASH_Update(cx, src, src_len); + HASH_End(cx, dest, &part, HASH_ResultLenContext(cx)); + HASH_Destroy(cx); + + return(SECSuccess); +} + +HASHContext * +HASH_Create(HASH_HashType type) +{ + void *hash_context = NULL; + HASHContext *ret = NULL; + + if ( ( type < HASH_AlgNULL ) || ( type >= HASH_AlgTOTAL ) ) { + return(NULL); + } + + hash_context = (* SECHashObjects[type].create)(); + if ( hash_context == NULL ) { + goto loser; + } + + ret = (HASHContext *)PORT_Alloc(sizeof(HASHContext)); + if ( ret == NULL ) { + goto loser; + } + + ret->hash_context = hash_context; + ret->hashobj = &SECHashObjects[type]; + + return(ret); + +loser: + if ( hash_context != NULL ) { + (* SECHashObjects[type].destroy)(hash_context, PR_TRUE); + } + + return(NULL); +} + + +HASHContext * +HASH_Clone(HASHContext *context) +{ + void *hash_context = NULL; + HASHContext *ret = NULL; + + hash_context = (* context->hashobj->clone)(context->hash_context); + if ( hash_context == NULL ) { + goto loser; + } + + ret = (HASHContext *)PORT_Alloc(sizeof(HASHContext)); + if ( ret == NULL ) { + goto loser; + } + + ret->hash_context = hash_context; + ret->hashobj = context->hashobj; + + return(ret); + +loser: + if ( hash_context != NULL ) { + (* context->hashobj->destroy)(hash_context, PR_TRUE); + } + + return(NULL); + +} + +void +HASH_Destroy(HASHContext *context) +{ + (* context->hashobj->destroy)(context->hash_context, PR_TRUE); + PORT_Free(context); + return; +} + + +void +HASH_Begin(HASHContext *context) +{ + (* context->hashobj->begin)(context->hash_context); + return; +} + + +void +HASH_Update(HASHContext *context, + const unsigned char *src, + unsigned int len) +{ + (* context->hashobj->update)(context->hash_context, src, len); + return; +} + +void +HASH_End(HASHContext *context, + unsigned char *result, + unsigned int *result_len, + unsigned int max_result_len) +{ + (* context->hashobj->end)(context->hash_context, result, result_len, + max_result_len); + return; +} + + + diff --git a/security/nss/lib/cryptohi/sechash.h b/security/nss/lib/cryptohi/sechash.h new file mode 100644 index 000000000..6a4fb3e40 --- /dev/null +++ b/security/nss/lib/cryptohi/sechash.h @@ -0,0 +1,77 @@ +#ifndef _HASH_H_ +#define _HASH_H_ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + * + * hash.h - public data structures and prototypes for the hashing library + * + * $Id$ + */ + +#include "seccomon.h" +#include "hasht.h" + +SEC_BEGIN_PROTOS + +/* +** Generic hash api. +*/ + +extern unsigned int HASH_ResultLen(HASH_HashType type); + +extern unsigned int HASH_ResultLenContext(HASHContext *context); + +extern SECStatus HASH_HashBuf(HASH_HashType type, + unsigned char *dest, + unsigned char *src, + uint32 src_len); + +extern HASHContext * HASH_Create(HASH_HashType type); + +extern HASHContext * HASH_Clone(HASHContext *context); + +extern void HASH_Destroy(HASHContext *context); + +extern void HASH_Begin(HASHContext *context); + +extern void HASH_Update(HASHContext *context, + const unsigned char *src, + unsigned int len); + +extern void HASH_End(HASHContext *context, + unsigned char *result, + unsigned int *result_len, + unsigned int max_result_len); + +SEC_END_PROTOS + +#endif /* _HASH_H_ */ diff --git a/security/nss/lib/cryptohi/seckey.c b/security/nss/lib/cryptohi/seckey.c new file mode 100644 index 000000000..4e1ba6734 --- /dev/null +++ b/security/nss/lib/cryptohi/seckey.c @@ -0,0 +1,1649 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ +#include "cryptohi.h" +#include "keyhi.h" +#include "secrng.h" +#include "secoid.h" +#include "secitem.h" +#include "secder.h" +#include "base64.h" +#include "secasn1.h" +#include "cert.h" +#include "pk11func.h" +#include "secerr.h" +#include "secdig.h" +#include "prtime.h" + +const SEC_ASN1Template CERT_SubjectPublicKeyInfoTemplate[] = { + { SEC_ASN1_SEQUENCE, + 0, NULL, sizeof(CERTSubjectPublicKeyInfo) }, + { SEC_ASN1_INLINE, + offsetof(CERTSubjectPublicKeyInfo,algorithm), + SECOID_AlgorithmIDTemplate }, + { SEC_ASN1_BIT_STRING, + offsetof(CERTSubjectPublicKeyInfo,subjectPublicKey), }, + { 0, } +}; + +const SEC_ASN1Template CERT_PublicKeyAndChallengeTemplate[] = +{ + { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTPublicKeyAndChallenge) }, + { SEC_ASN1_ANY, offsetof(CERTPublicKeyAndChallenge,spki) }, + { SEC_ASN1_IA5_STRING, offsetof(CERTPublicKeyAndChallenge,challenge) }, + { 0 } +}; + +const SEC_ASN1Template SECKEY_RSAPublicKeyTemplate[] = { + { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECKEYPublicKey) }, + { SEC_ASN1_INTEGER, offsetof(SECKEYPublicKey,u.rsa.modulus), }, + { SEC_ASN1_INTEGER, offsetof(SECKEYPublicKey,u.rsa.publicExponent), }, + { 0, } +}; + +const SEC_ASN1Template SECKEY_DSAPublicKeyTemplate[] = { + { SEC_ASN1_INTEGER, offsetof(SECKEYPublicKey,u.dsa.publicValue), }, + { 0, } +}; + +const SEC_ASN1Template SECKEY_PQGParamsTemplate[] = { + { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(PQGParams) }, + { SEC_ASN1_INTEGER, offsetof(PQGParams,prime) }, + { SEC_ASN1_INTEGER, offsetof(PQGParams,subPrime) }, + { SEC_ASN1_INTEGER, offsetof(PQGParams,base) }, + { 0, } +}; + +const SEC_ASN1Template SECKEY_DHPublicKeyTemplate[] = { + { SEC_ASN1_INTEGER, offsetof(SECKEYPublicKey,u.dh.publicValue), }, + { 0, } +}; + +const SEC_ASN1Template SECKEY_DHParamKeyTemplate[] = { + { SEC_ASN1_INTEGER, offsetof(SECKEYPublicKey,u.dh.prime), }, + { SEC_ASN1_INTEGER, offsetof(SECKEYPublicKey,u.dh.base), }, + { 0, } +}; + +const SEC_ASN1Template SECKEY_FortezzaParameterTemplate[] = { + { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(PQGParams) }, + { SEC_ASN1_OCTET_STRING, offsetof(PQGParams,prime), }, + { SEC_ASN1_OCTET_STRING, offsetof(PQGParams,subPrime), }, + { SEC_ASN1_OCTET_STRING, offsetof(PQGParams,base), }, + { 0 }, +}; + +const SEC_ASN1Template SECKEY_FortezzaDiffParameterTemplate[] = { + { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(DiffPQGParams) }, + { SEC_ASN1_INLINE, offsetof(DiffPQGParams,DiffKEAParams), + SECKEY_FortezzaParameterTemplate}, + { SEC_ASN1_INLINE, offsetof(DiffPQGParams,DiffDSAParams), + SECKEY_FortezzaParameterTemplate}, + { 0 }, +}; + +const SEC_ASN1Template SECKEY_FortezzaPreParamTemplate[] = { + { SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | + SEC_ASN1_CONTEXT_SPECIFIC | 1, offsetof(PQGDualParams,CommParams), + SECKEY_FortezzaParameterTemplate}, + { 0, } +}; + +const SEC_ASN1Template SECKEY_FortezzaAltPreParamTemplate[] = { + { SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | + SEC_ASN1_CONTEXT_SPECIFIC | 0, offsetof(PQGDualParams,DiffParams), + SECKEY_FortezzaDiffParameterTemplate}, + { 0, } +}; + +const SEC_ASN1Template SECKEY_KEAPublicKeyTemplate[] = { + { SEC_ASN1_INTEGER, offsetof(SECKEYPublicKey,u.kea.publicValue), }, + { 0, } +}; + +const SEC_ASN1Template SECKEY_KEAParamsTemplate[] = { + { SEC_ASN1_OCTET_STRING, offsetof(SECKEYPublicKey,u.kea.params.hash), }, + { 0, } +}; + + +/* + * NOTE: This only generates RSA Private Key's. If you need more, + * We need to pass in some more params... + */ +SECKEYPrivateKey * +SECKEY_CreateRSAPrivateKey(int keySizeInBits,SECKEYPublicKey **pubk, void *cx) +{ + SECKEYPrivateKey *privk; + PK11SlotInfo *slot = PK11_GetBestSlot(CKM_RSA_PKCS_KEY_PAIR_GEN,cx); + PK11RSAGenParams param; + + param.keySizeInBits = keySizeInBits; + param.pe = 65537L; + + privk = PK11_GenerateKeyPair(slot,CKM_RSA_PKCS_KEY_PAIR_GEN,¶m,pubk, + PR_FALSE, PR_TRUE, cx); + PK11_FreeSlot(slot); + return(privk); +} + +void +SECKEY_DestroyPrivateKey(SECKEYPrivateKey *privk) +{ + if (privk) { + if (privk->pkcs11Slot) { + if (privk->pkcs11IsTemp) { + PK11_DestroyObject(privk->pkcs11Slot,privk->pkcs11ID); + } + PK11_FreeSlot(privk->pkcs11Slot); + + } + if (privk->arena) { + PORT_FreeArena(privk->arena, PR_TRUE); + } + } +} + +void +SECKEY_DestroyPublicKey(SECKEYPublicKey *pubk) +{ + if (pubk) { + if (pubk->pkcs11Slot) { + PK11_DestroyObject(pubk->pkcs11Slot,pubk->pkcs11ID); + PK11_FreeSlot(pubk->pkcs11Slot); + } + if (pubk->arena) { + PORT_FreeArena(pubk->arena, PR_FALSE); + } + } +} + +SECStatus +SECKEY_CopySubjectPublicKeyInfo(PRArenaPool *arena, + CERTSubjectPublicKeyInfo *to, + CERTSubjectPublicKeyInfo *from) +{ + SECStatus rv; + + rv = SECOID_CopyAlgorithmID(arena, &to->algorithm, &from->algorithm); + if (rv == SECSuccess) + rv = SECITEM_CopyItem(arena, &to->subjectPublicKey, &from->subjectPublicKey); + + return rv; +} + +SECStatus +SECKEY_KEASetParams(KEAParams * params, SECKEYPublicKey * pubKey) { + + if (pubKey->keyType == fortezzaKey) { + /* the key is a fortezza V1 public key */ + + /* obtain hash of pubkey->u.fortezza.params.prime.data + + pubkey->u.fortezza.params.subPrime.data + + pubkey->u.fortezza.params.base.data */ + + /* store hash in params->hash */ + + } else if (pubKey->keyType == keaKey) { + + /* the key is a new fortezza KEA public key. */ + SECITEM_CopyItem(pubKey->arena, ¶ms->hash, + &pubKey->u.kea.params.hash ); + + } else { + + /* the key has no KEA parameters */ + return SECFailure; + } + +} + + +SECStatus +SECKEY_KEAParamCompare(CERTCertificate *cert1,CERTCertificate *cert2) +{ + + SECStatus rv; + SECOidData *oid=NULL; + CERTSubjectPublicKeyInfo * subjectSpki=NULL; + CERTSubjectPublicKeyInfo * issuerSpki=NULL; + CERTCertificate *issuerCert = NULL; + + SECKEYPublicKey *pubKey1 = 0; + SECKEYPublicKey *pubKey2 = 0; + + KEAParams params1; + KEAParams params2; + + + rv = SECFailure; + + /* get cert1's public key */ + pubKey1 = CERT_ExtractPublicKey(cert1); + if ( !pubKey1 ) { + return(SECFailure); + } + + + /* get cert2's public key */ + pubKey2 = CERT_ExtractPublicKey(cert2); + if ( !pubKey2 ) { + return(SECFailure); + } + + /* handle the case when both public keys are new + * fortezza KEA public keys. */ + + if ((pubKey1->keyType == keaKey) && + (pubKey2->keyType == keaKey) ) { + + rv = (SECStatus)SECITEM_CompareItem(&pubKey1->u.kea.params.hash, + &pubKey2->u.kea.params.hash); + goto done; + } + + /* handle the case when both public keys are old fortezza + * public keys. */ + + if ((pubKey1->keyType == fortezzaKey) && + (pubKey2->keyType == fortezzaKey) ) { + + rv = (SECStatus)SECITEM_CompareItem(&pubKey1->u.fortezza.keaParams.prime, + &pubKey2->u.fortezza.keaParams.prime); + + if (rv == SECEqual) { + rv = (SECStatus)SECITEM_CompareItem(&pubKey1->u.fortezza.keaParams.subPrime, + &pubKey2->u.fortezza.keaParams.subPrime); + } + + if (rv == SECEqual) { + rv = (SECStatus)SECITEM_CompareItem(&pubKey1->u.fortezza.keaParams.base, + &pubKey2->u.fortezza.keaParams.base); + } + + goto done; + } + + + /* handle the case when the public keys are a mixture of + * old and new. */ + + rv = SECKEY_KEASetParams(¶ms1, pubKey1); + if (rv != SECSuccess) return rv; + + rv = SECKEY_KEASetParams(¶ms2, pubKey2); + if (rv != SECSuccess) return rv; + + rv = (SECStatus)SECITEM_CompareItem(¶ms1.hash, ¶ms2.hash); + +done: + SECKEY_DestroyPublicKey(pubKey1); + SECKEY_DestroyPublicKey(pubKey2); + + return rv; /* returns SECEqual if parameters are equal */ + +} + + +/* Procedure to update the pqg parameters for a cert's public key. + * pqg parameters only need to be updated for DSA and fortezza certificates. + * The procedure uses calls to itself recursively to update a certificate + * issuer's pqg parameters. Some important rules are: + * - Do nothing if the cert already has PQG parameters. + * - If the cert does not have PQG parameters, obtain them from the issuer. + * - A valid cert chain cannot have a DSA or Fortezza cert without + * pqg parameters that has a parent that is not a DSA or Fortezza cert. + * - pqg paramters are stored in two different formats: the standard + * DER encoded format and the fortezza-only wrapped format. The params + * should be copied from issuer to subject cert without modifying the + * formats. The public key extraction code will deal with the different + * formats at the time of extraction. */ + +SECStatus +seckey_UpdateCertPQGChain(CERTCertificate * subjectCert, int count) +{ + SECStatus rv, rvCompare; + SECOidData *oid=NULL; + int tag; + CERTSubjectPublicKeyInfo * subjectSpki=NULL; + CERTSubjectPublicKeyInfo * issuerSpki=NULL; + CERTCertificate *issuerCert = NULL; + + rv = SECSuccess; + + /* increment cert chain length counter*/ + count++; + + /* check if cert chain length exceeds the maximum length*/ + if (count > CERT_MAX_CERT_CHAIN) { + return SECFailure; + } + + oid = SECOID_FindOID(&subjectCert->subjectPublicKeyInfo.algorithm.algorithm); + if (oid != NULL) { + tag = oid->offset; + + /* Check if cert has a DSA or Fortezza public key. If not, return + * success since no PQG params need to be updated. */ + + if ( (tag != SEC_OID_MISSI_KEA_DSS_OLD) && + (tag != SEC_OID_MISSI_DSS_OLD) && + (tag != SEC_OID_MISSI_KEA_DSS) && + (tag != SEC_OID_MISSI_DSS) && + (tag != SEC_OID_ANSIX9_DSA_SIGNATURE) && + (tag != SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST) && + (tag != SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST) ) { + + return SECSuccess; + } + } else { + return SECFailure; /* return failure if oid is NULL */ + } + + /* if cert has PQG parameters, return success */ + + subjectSpki=&subjectCert->subjectPublicKeyInfo; + + if (subjectSpki->algorithm.parameters.len != 0) { + return SECSuccess; + } + + /* check if the cert is self-signed */ + rvCompare = (SECStatus)SECITEM_CompareItem(&subjectCert->derSubject, + &subjectCert->derIssuer); + if (rvCompare == SECEqual) { + /* fail since cert is self-signed and has no pqg params. */ + return SECFailure; + } + + /* get issuer cert */ + issuerCert = CERT_FindCertIssuer(subjectCert, PR_Now(), certUsageAnyCA); + if ( ! issuerCert ) { + return SECFailure; + } + + /* if parent is not DSA or fortezza, return failure since + we don't allow this case. */ + + oid = SECOID_FindOID(&issuerCert->subjectPublicKeyInfo.algorithm.algorithm); + if (oid != NULL) { + tag = oid->offset; + + /* Check if issuer cert has a DSA or Fortezza public key. If not, + * return failure. */ + + if ( (tag != SEC_OID_MISSI_KEA_DSS_OLD) && + (tag != SEC_OID_MISSI_DSS_OLD) && + (tag != SEC_OID_MISSI_KEA_DSS) && + (tag != SEC_OID_MISSI_DSS) && + (tag != SEC_OID_ANSIX9_DSA_SIGNATURE) && + (tag != SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST) && + (tag != SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST) ) { + + return SECFailure; + } + } else { + return SECFailure; /* return failure if oid is NULL */ + } + + + /* at this point the subject cert has no pqg parameters and the + * issuer cert has a DSA or fortezza public key. Update the issuer's + * pqg parameters with a recursive call to this same function. */ + + rv = seckey_UpdateCertPQGChain(issuerCert, count); + if (rv != SECSuccess) return rv; + + /* ensure issuer has pqg parameters */ + + issuerSpki=&issuerCert->subjectPublicKeyInfo; + if (issuerSpki->algorithm.parameters.len == 0) { + rv = SECFailure; + } + + /* if update was successful and pqg params present, then copy the + * parameters to the subject cert's key. */ + + if (rv == SECSuccess) { + rv = SECITEM_CopyItem(subjectCert->arena, + &subjectSpki->algorithm.parameters, + &issuerSpki->algorithm.parameters); + } + + return rv; + +} + + +SECStatus +SECKEY_UpdateCertPQG(CERTCertificate * subjectCert) +{ + return(seckey_UpdateCertPQGChain(subjectCert,0)); +} + + +/* Decode the PQG parameters. The params could be stored in two + * possible formats, the old fortezza-only wrapped format or + * the standard DER encoded format. Store the decoded parameters in an + * old fortezza cert data structure */ + +SECStatus +SECKEY_FortezzaDecodePQGtoOld(PRArenaPool *arena, SECKEYPublicKey *pubk, + SECItem *params) { + SECStatus rv; + PQGDualParams dual_params; + + if (params == NULL) return SECFailure; + + if (params->data == NULL) return SECFailure; + + /* Check if params use the standard format. + * The value 0xa1 will appear in the first byte of the parameter data + * if the PQG parameters are not using the standard format. This + * code should be changed to use a better method to detect non-standard + * parameters. */ + + if ((params->data[0] != 0xa1) && + (params->data[0] != 0xa0)) { + + /* PQG params are in the standard format */ + + /* Store DSA PQG parameters */ + rv = SEC_ASN1DecodeItem(arena, &pubk->u.fortezza.params, + SECKEY_PQGParamsTemplate, + params); + + if (rv == SECSuccess) { + + /* Copy the DSA PQG parameters to the KEA PQG parameters. */ + rv = SECITEM_CopyItem(arena, &pubk->u.fortezza.keaParams.prime, + &pubk->u.fortezza.params.prime); + if (rv != SECSuccess) return rv; + rv = SECITEM_CopyItem(arena, &pubk->u.fortezza.keaParams.subPrime, + &pubk->u.fortezza.params.subPrime); + if (rv != SECSuccess) return rv; + rv = SECITEM_CopyItem(arena, &pubk->u.fortezza.keaParams.base, + &pubk->u.fortezza.params.base); + if (rv != SECSuccess) return rv; + } + + } else { + + dual_params.CommParams.prime.len = 0; + dual_params.CommParams.subPrime.len = 0; + dual_params.CommParams.base.len = 0; + dual_params.DiffParams.DiffDSAParams.prime.len = 0; + dual_params.DiffParams.DiffDSAParams.subPrime.len = 0; + dual_params.DiffParams.DiffDSAParams.base.len = 0; + + /* else the old fortezza-only wrapped format is used. */ + + if (params->data[0] == 0xa1) { + rv = SEC_ASN1DecodeItem(arena, &dual_params, + SECKEY_FortezzaPreParamTemplate, params); + } else { + rv = SEC_ASN1DecodeItem(arena, &dual_params, + SECKEY_FortezzaAltPreParamTemplate, params); + } + + if (rv < 0) return rv; + + if ( (dual_params.CommParams.prime.len > 0) && + (dual_params.CommParams.subPrime.len > 0) && + (dual_params.CommParams.base.len > 0) ) { + /* copy in common params */ + + rv = SECITEM_CopyItem(arena, &pubk->u.fortezza.params.prime, + &dual_params.CommParams.prime); + if (rv != SECSuccess) return rv; + rv = SECITEM_CopyItem(arena, &pubk->u.fortezza.params.subPrime, + &dual_params.CommParams.subPrime); + if (rv != SECSuccess) return rv; + rv = SECITEM_CopyItem(arena, &pubk->u.fortezza.params.base, + &dual_params.CommParams.base); + + /* Copy the DSA PQG parameters to the KEA PQG parameters. */ + rv = SECITEM_CopyItem(arena, &pubk->u.fortezza.keaParams.prime, + &pubk->u.fortezza.params.prime); + if (rv != SECSuccess) return rv; + rv = SECITEM_CopyItem(arena, &pubk->u.fortezza.keaParams.subPrime, + &pubk->u.fortezza.params.subPrime); + if (rv != SECSuccess) return rv; + rv = SECITEM_CopyItem(arena, &pubk->u.fortezza.keaParams.base, + &pubk->u.fortezza.params.base); + if (rv != SECSuccess) return rv; + + } else { + + /* else copy in different params */ + + /* copy DSA PQG parameters */ + rv = SECITEM_CopyItem(arena, &pubk->u.fortezza.params.prime, + &dual_params.DiffParams.DiffDSAParams.prime); + if (rv != SECSuccess) return rv; + rv = SECITEM_CopyItem(arena, &pubk->u.fortezza.params.subPrime, + &dual_params.DiffParams.DiffDSAParams.subPrime); + if (rv != SECSuccess) return rv; + rv = SECITEM_CopyItem(arena, &pubk->u.fortezza.params.base, + &dual_params.DiffParams.DiffDSAParams.base); + + /* copy KEA PQG parameters */ + + rv = SECITEM_CopyItem(arena, &pubk->u.fortezza.keaParams.prime, + &dual_params.DiffParams.DiffKEAParams.prime); + if (rv != SECSuccess) return rv; + rv = SECITEM_CopyItem(arena, &pubk->u.fortezza.keaParams.subPrime, + &dual_params.DiffParams.DiffKEAParams.subPrime); + if (rv != SECSuccess) return rv; + rv = SECITEM_CopyItem(arena, &pubk->u.fortezza.keaParams.base, + &dual_params.DiffParams.DiffKEAParams.base); + } + + } + return rv; +} + + +/* Decode the DSA PQG parameters. The params could be stored in two + * possible formats, the old fortezza-only wrapped format or + * the normal standard format. Store the decoded parameters in + * a V3 certificate data structure. */ + +SECStatus +SECKEY_DSADecodePQG(PRArenaPool *arena, SECKEYPublicKey *pubk, SECItem *params) { + SECStatus rv; + PQGDualParams dual_params; + + if (params == NULL) return SECFailure; + + if (params->data == NULL) return SECFailure; + + /* Check if params use the standard format. + * The value 0xa1 will appear in the first byte of the parameter data + * if the PQG parameters are not using the standard format. This + * code should be changed to use a better method to detect non-standard + * parameters. */ + + if ((params->data[0] != 0xa1) && + (params->data[0] != 0xa0)) { + + /* PQG params are in the standard format */ + rv = SEC_ASN1DecodeItem(arena, &pubk->u.dsa.params, + SECKEY_PQGParamsTemplate, + params); + } else { + + dual_params.CommParams.prime.len = 0; + dual_params.CommParams.subPrime.len = 0; + dual_params.CommParams.base.len = 0; + dual_params.DiffParams.DiffDSAParams.prime.len = 0; + dual_params.DiffParams.DiffDSAParams.subPrime.len = 0; + dual_params.DiffParams.DiffDSAParams.base.len = 0; + + /* else the old fortezza-only wrapped format is used. */ + if (params->data[0] == 0xa1) { + rv = SEC_ASN1DecodeItem(arena, &dual_params, + SECKEY_FortezzaPreParamTemplate, params); + } else { + rv = SEC_ASN1DecodeItem(arena, &dual_params, + SECKEY_FortezzaAltPreParamTemplate, params); + } + + if (rv < 0) return rv; + + if ( (dual_params.CommParams.prime.len > 0) && + (dual_params.CommParams.subPrime.len > 0) && + (dual_params.CommParams.base.len > 0) ) { + /* copy in common params */ + + rv = SECITEM_CopyItem(arena, &pubk->u.dsa.params.prime, + &dual_params.CommParams.prime); + if (rv != SECSuccess) return rv; + rv = SECITEM_CopyItem(arena, &pubk->u.dsa.params.subPrime, + &dual_params.CommParams.subPrime); + if (rv != SECSuccess) return rv; + rv = SECITEM_CopyItem(arena, &pubk->u.dsa.params.base, + &dual_params.CommParams.base); + + } else { + + /* else copy in different params */ + + /* copy DSA PQG parameters */ + rv = SECITEM_CopyItem(arena, &pubk->u.dsa.params.prime, + &dual_params.DiffParams.DiffDSAParams.prime); + if (rv != SECSuccess) return rv; + rv = SECITEM_CopyItem(arena, &pubk->u.dsa.params.subPrime, + &dual_params.DiffParams.DiffDSAParams.subPrime); + if (rv != SECSuccess) return rv; + rv = SECITEM_CopyItem(arena, &pubk->u.dsa.params.base, + &dual_params.DiffParams.DiffDSAParams.base); + + } + } + return rv; +} + + + +/* Decodes the DER encoded fortezza public key and stores the results in a + * structure of type SECKEYPublicKey. */ + +SECStatus +SECKEY_FortezzaDecodeCertKey(PRArenaPool *arena, SECKEYPublicKey *pubk, + SECItem *rawkey, SECItem *params) { + + unsigned char *rawptr = rawkey->data; + unsigned char *end = rawkey->data + rawkey->len; + unsigned char *clearptr; + + /* first march down and decode the raw key data */ + + /* version */ + pubk->u.fortezza.KEAversion = *rawptr++; + if (*rawptr++ != 0x01) { + return SECFailure; + } + + /* KMID */ + PORT_Memcpy(pubk->u.fortezza.KMID,rawptr, + sizeof(pubk->u.fortezza.KMID)); + rawptr += sizeof(pubk->u.fortezza.KMID); + + /* clearance (the string up to the first byte with the hi-bit on */ + clearptr = rawptr; + while ((rawptr < end) && (*rawptr++ & 0x80)); + + if (rawptr >= end) { return SECFailure; } + pubk->u.fortezza.clearance.len = rawptr - clearptr; + pubk->u.fortezza.clearance.data = + (unsigned char*)PORT_ArenaZAlloc(arena,pubk->u.fortezza.clearance.len); + if (pubk->u.fortezza.clearance.data == NULL) { + return SECFailure; + } + PORT_Memcpy(pubk->u.fortezza.clearance.data,clearptr, + pubk->u.fortezza.clearance.len); + + /* KEAPrivilege (the string up to the first byte with the hi-bit on */ + clearptr = rawptr; + while ((rawptr < end) && (*rawptr++ & 0x80)); + if (rawptr >= end) { return SECFailure; } + pubk->u.fortezza.KEApriviledge.len = rawptr - clearptr; + pubk->u.fortezza.KEApriviledge.data = + (unsigned char*)PORT_ArenaZAlloc(arena,pubk->u.fortezza.KEApriviledge.len); + if (pubk->u.fortezza.KEApriviledge.data == NULL) { + return SECFailure; + } + PORT_Memcpy(pubk->u.fortezza.KEApriviledge.data,clearptr, + pubk->u.fortezza.KEApriviledge.len); + + + /* now copy the key. The next to bytes are the key length, and the + * key follows */ + pubk->u.fortezza.KEAKey.len = (*rawptr << 8) | rawptr[1]; + + rawptr += 2; + if (rawptr+pubk->u.fortezza.KEAKey.len > end) { return SECFailure; } + pubk->u.fortezza.KEAKey.data = + (unsigned char*)PORT_ArenaZAlloc(arena,pubk->u.fortezza.KEAKey.len); + if (pubk->u.fortezza.KEAKey.data == NULL) { + return SECFailure; + } + PORT_Memcpy(pubk->u.fortezza.KEAKey.data,rawptr, + pubk->u.fortezza.KEAKey.len); + rawptr += pubk->u.fortezza.KEAKey.len; + + /* shared key */ + if (rawptr >= end) { + pubk->u.fortezza.DSSKey.len = pubk->u.fortezza.KEAKey.len; + /* this depends on the fact that we are going to get freed with an + * ArenaFree call. We cannot free DSSKey and KEAKey separately */ + pubk->u.fortezza.DSSKey.data= + pubk->u.fortezza.KEAKey.data; + pubk->u.fortezza.DSSpriviledge.len = + pubk->u.fortezza.KEApriviledge.len; + pubk->u.fortezza.DSSpriviledge.data = + pubk->u.fortezza.DSSpriviledge.data; + goto done; + } + + + /* DSS Version is next */ + pubk->u.fortezza.DSSversion = *rawptr++; + + if (*rawptr++ != 2) { + return SECFailure; + } + + /* DSSPrivilege (the string up to the first byte with the hi-bit on */ + clearptr = rawptr; + while ((rawptr < end) && (*rawptr++ & 0x80)); + if (rawptr >= end) { return SECFailure; } + pubk->u.fortezza.DSSpriviledge.len = rawptr - clearptr; + pubk->u.fortezza.DSSpriviledge.data = + (unsigned char*)PORT_ArenaZAlloc(arena,pubk->u.fortezza.DSSpriviledge.len); + if (pubk->u.fortezza.DSSpriviledge.data == NULL) { + return SECFailure; + } + PORT_Memcpy(pubk->u.fortezza.DSSpriviledge.data,clearptr, + pubk->u.fortezza.DSSpriviledge.len); + + /* finally copy the DSS key. The next to bytes are the key length, + * and the key follows */ + pubk->u.fortezza.DSSKey.len = (*rawptr << 8) | rawptr[1]; + + rawptr += 2; + if (rawptr+pubk->u.fortezza.DSSKey.len > end){ return SECFailure; } + pubk->u.fortezza.DSSKey.data = + (unsigned char*)PORT_ArenaZAlloc(arena,pubk->u.fortezza.DSSKey.len); + if (pubk->u.fortezza.DSSKey.data == NULL) { + return SECFailure; + } + PORT_Memcpy(pubk->u.fortezza.DSSKey.data,rawptr, + pubk->u.fortezza.DSSKey.len); + + /* ok, now we decode the parameters */ +done: + + return SECKEY_FortezzaDecodePQGtoOld(arena, pubk, params); +} + + +/* Function used to determine what kind of cert we are dealing with. */ +KeyType +CERT_GetCertKeyType (CERTSubjectPublicKeyInfo *spki) { + int tag; + KeyType keyType; + + tag = SECOID_GetAlgorithmTag(&spki->algorithm); + switch (tag) { + case SEC_OID_X500_RSA_ENCRYPTION: + case SEC_OID_PKCS1_RSA_ENCRYPTION: + keyType = rsaKey; + break; + case SEC_OID_ANSIX9_DSA_SIGNATURE: + keyType = dsaKey; + break; + case SEC_OID_MISSI_KEA_DSS_OLD: + case SEC_OID_MISSI_KEA_DSS: + case SEC_OID_MISSI_DSS_OLD: + case SEC_OID_MISSI_DSS: + keyType = fortezzaKey; + break; + case SEC_OID_MISSI_KEA: + case SEC_OID_MISSI_ALT_KEA: + keyType = keaKey; + break; + case SEC_OID_X942_DIFFIE_HELMAN_KEY: + keyType = dhKey; + default: + keyType = nullKey; + } + return keyType; +} + +static SECKEYPublicKey * +seckey_ExtractPublicKey(CERTSubjectPublicKeyInfo *spki) +{ + SECKEYPublicKey *pubk; + SECItem os; + SECStatus rv; + PRArenaPool *arena; + int tag; + + arena = PORT_NewArena (DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) + return NULL; + + pubk = (SECKEYPublicKey *) PORT_ArenaZAlloc(arena, sizeof(SECKEYPublicKey)); + if (pubk == NULL) { + PORT_FreeArena (arena, PR_FALSE); + return NULL; + } + + pubk->arena = arena; + pubk->pkcs11Slot = 0; + pubk->pkcs11ID = CK_INVALID_KEY; + + + /* Convert bit string length from bits to bytes */ + os = spki->subjectPublicKey; + DER_ConvertBitString (&os); + + tag = SECOID_GetAlgorithmTag(&spki->algorithm); + switch ( tag ) { + case SEC_OID_X500_RSA_ENCRYPTION: + case SEC_OID_PKCS1_RSA_ENCRYPTION: + pubk->keyType = rsaKey; + rv = SEC_ASN1DecodeItem(arena, pubk, SECKEY_RSAPublicKeyTemplate, &os); + if (rv == SECSuccess) + return pubk; + break; + case SEC_OID_ANSIX9_DSA_SIGNATURE: + pubk->keyType = dsaKey; + rv = SEC_ASN1DecodeItem(arena, pubk, SECKEY_DSAPublicKeyTemplate, &os); + if (rv != SECSuccess) break; + + rv = SECKEY_DSADecodePQG(arena, pubk, + &spki->algorithm.parameters); + + if (rv == SECSuccess) return pubk; + break; + case SEC_OID_X942_DIFFIE_HELMAN_KEY: + pubk->keyType = dhKey; + rv = SEC_ASN1DecodeItem(arena, pubk, SECKEY_DHPublicKeyTemplate, &os); + if (rv != SECSuccess) break; + + rv = SEC_ASN1DecodeItem(arena, &pubk->u.dh, + SECKEY_DHParamKeyTemplate, + &spki->algorithm.parameters); + + if (rv == SECSuccess) return pubk; + break; + case SEC_OID_MISSI_KEA_DSS_OLD: + case SEC_OID_MISSI_KEA_DSS: + case SEC_OID_MISSI_DSS_OLD: + case SEC_OID_MISSI_DSS: + pubk->keyType = fortezzaKey; + rv = SECKEY_FortezzaDecodeCertKey(arena, pubk, &os, + &spki->algorithm.parameters); + if (rv == SECSuccess) + return pubk; + break; + + case SEC_OID_MISSI_KEA: + pubk->keyType = keaKey; + + rv = SEC_ASN1DecodeItem(arena, pubk, + SECKEY_KEAPublicKeyTemplate, &os); + if (rv != SECSuccess) break; + + + rv = SEC_ASN1DecodeItem(arena, pubk, SECKEY_KEAParamsTemplate, + &spki->algorithm.parameters); + + if (rv == SECSuccess) + return pubk; + + break; + + case SEC_OID_MISSI_ALT_KEA: + pubk->keyType = keaKey; + + rv = SECITEM_CopyItem(arena,&pubk->u.kea.publicValue,&os); + if (rv != SECSuccess) break; + + rv = SEC_ASN1DecodeItem(arena, pubk, SECKEY_KEAParamsTemplate, + &spki->algorithm.parameters); + + if (rv == SECSuccess) + return pubk; + + break; + + + default: + rv = SECFailure; + break; + } + + SECKEY_DestroyPublicKey (pubk); + return NULL; +} + +SECKEYPublicKey * +CERT_ExtractPublicKey(CERTCertificate *cert) +{ + SECStatus rv; + + rv = SECKEY_UpdateCertPQG(cert); + if (rv != SECSuccess) return NULL; + + return seckey_ExtractPublicKey(&cert->subjectPublicKeyInfo); +} + +/* + * Get the public key for the fortezza KMID. NOTE this requires the + * PQG paramters to be set. We probably should have a fortezza call that + * just extracts the kmid for us directly so this function can work + * without having the whole cert chain + */ +SECKEYPublicKey * +CERT_KMIDPublicKey(CERTCertificate *cert) +{ + return seckey_ExtractPublicKey(&cert->subjectPublicKeyInfo); +} + +/* returns key strength in bytes (not bits) */ +unsigned +SECKEY_PublicKeyStrength(SECKEYPublicKey *pubk) +{ + unsigned char b0; + + /* interpret modulus length as key strength... in + * fortezza that's the public key length */ + + switch (pubk->keyType) { + case rsaKey: + b0 = pubk->u.rsa.modulus.data[0]; + return b0 ? pubk->u.rsa.modulus.len : pubk->u.rsa.modulus.len - 1; + case dsaKey: + b0 = pubk->u.dsa.publicValue.data[0]; + return b0 ? pubk->u.dsa.publicValue.len : + pubk->u.dsa.publicValue.len - 1; + case dhKey: + b0 = pubk->u.dh.publicValue.data[0]; + return b0 ? pubk->u.dh.publicValue.len : + pubk->u.dh.publicValue.len - 1; + case fortezzaKey: + return MAX(pubk->u.fortezza.KEAKey.len, pubk->u.fortezza.DSSKey.len); + default: + break; + } + return 0; +} + +SECKEYPrivateKey * +SECKEY_CopyPrivateKey(SECKEYPrivateKey *privk) +{ + SECKEYPrivateKey *copyk; + PRArenaPool *arena; + + if (privk == NULL) { + return NULL; + } + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + PORT_SetError (SEC_ERROR_NO_MEMORY); + return NULL; + } + + copyk = (SECKEYPrivateKey *) PORT_ArenaZAlloc (arena, sizeof (SECKEYPrivateKey)); + if (copyk) { + copyk->arena = arena; + copyk->keyType = privk->keyType; + + /* copy the PKCS #11 parameters */ + copyk->pkcs11Slot = PK11_ReferenceSlot(privk->pkcs11Slot); + /* if the key we're referencing was a temparary key we have just + * created, that we want to go away when we're through, we need + * to make a copy of it */ + if (privk->pkcs11IsTemp) { + copyk->pkcs11ID = + PK11_CopyKey(privk->pkcs11Slot,privk->pkcs11ID); + if (copyk->pkcs11ID == CK_INVALID_KEY) goto fail; + } else { + copyk->pkcs11ID = privk->pkcs11ID; + } + copyk->pkcs11IsTemp = privk->pkcs11IsTemp; + copyk->wincx = privk->wincx; + return copyk; + } else { + PORT_SetError (SEC_ERROR_NO_MEMORY); + } + +fail: + PORT_FreeArena (arena, PR_FALSE); + return NULL; +} + +SECKEYPublicKey * +SECKEY_CopyPublicKey(SECKEYPublicKey *pubk) +{ + SECKEYPublicKey *copyk; + PRArenaPool *arena; + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + PORT_SetError (SEC_ERROR_NO_MEMORY); + return NULL; + } + + copyk = (SECKEYPublicKey *) PORT_ArenaZAlloc (arena, sizeof (SECKEYPublicKey)); + if (copyk != NULL) { + SECStatus rv = SECSuccess; + + copyk->arena = arena; + copyk->keyType = pubk->keyType; + copyk->pkcs11Slot = NULL; /* go get own reference */ + copyk->pkcs11ID = CK_INVALID_KEY; + switch (pubk->keyType) { + case rsaKey: + rv = SECITEM_CopyItem(arena, ©k->u.rsa.modulus, + &pubk->u.rsa.modulus); + if (rv == SECSuccess) { + rv = SECITEM_CopyItem (arena, ©k->u.rsa.publicExponent, + &pubk->u.rsa.publicExponent); + if (rv == SECSuccess) + return copyk; + } + break; + case dsaKey: + rv = SECITEM_CopyItem(arena, ©k->u.dsa.publicValue, + &pubk->u.dsa.publicValue); + if (rv != SECSuccess) break; + rv = SECITEM_CopyItem(arena, ©k->u.dsa.params.prime, + &pubk->u.dsa.params.prime); + if (rv != SECSuccess) break; + rv = SECITEM_CopyItem(arena, ©k->u.dsa.params.subPrime, + &pubk->u.dsa.params.subPrime); + if (rv != SECSuccess) break; + rv = SECITEM_CopyItem(arena, ©k->u.dsa.params.base, + &pubk->u.dsa.params.base); + break; + case keaKey: + rv = SECITEM_CopyItem(arena, ©k->u.kea.publicValue, + &pubk->u.kea.publicValue); + if (rv != SECSuccess) break; + rv = SECITEM_CopyItem(arena, ©k->u.kea.params.hash, + &pubk->u.kea.params.hash); + break; + case fortezzaKey: + copyk->u.fortezza.KEAversion = pubk->u.fortezza.KEAversion; + copyk->u.fortezza.DSSversion = pubk->u.fortezza.DSSversion; + PORT_Memcpy(copyk->u.fortezza.KMID, pubk->u.fortezza.KMID, + sizeof(pubk->u.fortezza.KMID)); + rv = SECITEM_CopyItem(arena, ©k->u.fortezza.clearance, + &pubk->u.fortezza.clearance); + if (rv != SECSuccess) break; + rv = SECITEM_CopyItem(arena, ©k->u.fortezza.KEApriviledge, + &pubk->u.fortezza.KEApriviledge); + if (rv != SECSuccess) break; + rv = SECITEM_CopyItem(arena, ©k->u.fortezza.DSSpriviledge, + &pubk->u.fortezza.DSSpriviledge); + if (rv != SECSuccess) break; + rv = SECITEM_CopyItem(arena, ©k->u.fortezza.KEAKey, + &pubk->u.fortezza.KEAKey); + if (rv != SECSuccess) break; + rv = SECITEM_CopyItem(arena, ©k->u.fortezza.DSSKey, + &pubk->u.fortezza.DSSKey); + if (rv != SECSuccess) break; + rv = SECITEM_CopyItem(arena, ©k->u.fortezza.params.prime, + &pubk->u.fortezza.params.prime); + if (rv != SECSuccess) break; + rv = SECITEM_CopyItem(arena, ©k->u.fortezza.params.subPrime, + &pubk->u.fortezza.params.subPrime); + if (rv != SECSuccess) break; + rv = SECITEM_CopyItem(arena, ©k->u.fortezza.params.base, + &pubk->u.fortezza.params.base); + if (rv != SECSuccess) break; + rv = SECITEM_CopyItem(arena, ©k->u.fortezza.keaParams.prime, + &pubk->u.fortezza.keaParams.prime); + if (rv != SECSuccess) break; + rv = SECITEM_CopyItem(arena, ©k->u.fortezza.keaParams.subPrime, + &pubk->u.fortezza.keaParams.subPrime); + if (rv != SECSuccess) break; + rv = SECITEM_CopyItem(arena, ©k->u.fortezza.keaParams.base, + &pubk->u.fortezza.keaParams.base); + break; + case dhKey: + rv = SECITEM_CopyItem(arena,©k->u.dh.prime,&pubk->u.dh.prime); + if (rv != SECSuccess) break; + rv = SECITEM_CopyItem(arena,©k->u.dh.base,&pubk->u.dh.base); + if (rv != SECSuccess) break; + rv = SECITEM_CopyItem(arena, ©k->u.dh.publicValue, + &pubk->u.dh.publicValue); + break; + case nullKey: + return copyk; + default: + rv = SECFailure; + break; + } + if (rv == SECSuccess) + return copyk; + + SECKEY_DestroyPublicKey (copyk); + } else { + PORT_SetError (SEC_ERROR_NO_MEMORY); + } + + PORT_FreeArena (arena, PR_FALSE); + return NULL; +} + + +SECKEYPublicKey * +SECKEY_ConvertToPublicKey(SECKEYPrivateKey *privk) +{ + SECKEYPublicKey *pubk; + PRArenaPool *arena; + CERTCertificate *cert; + SECStatus rv; + + /* + * First try to look up the cert. + */ + cert = PK11_GetCertFromPrivateKey(privk); + if (cert) { + pubk = CERT_ExtractPublicKey(cert); + CERT_DestroyCertificate(cert); + return pubk; + } + + /* couldn't find the cert, build pub key by hand */ + arena = PORT_NewArena (DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + PORT_SetError (SEC_ERROR_NO_MEMORY); + return NULL; + } + pubk = (SECKEYPublicKey *)PORT_ArenaZAlloc(arena, + sizeof (SECKEYPublicKey)); + if (pubk == NULL) { + PORT_FreeArena(arena,PR_FALSE); + return NULL; + } + pubk->keyType = privk->keyType; + pubk->pkcs11Slot = NULL; + pubk->pkcs11ID = CK_INVALID_KEY; + pubk->arena = arena; + + /* + * fortezza is at the head of this switch, since we don't want to + * allocate an arena... CERT_ExtractPublicKey will to that for us. + */ + switch(privk->keyType) { + case fortezzaKey: + case nullKey: + case dhKey: + case dsaKey: + /* Nothing to query, if the cert isn't there, we're done -- no way + * to get the public key */ + break; + case rsaKey: + rv = PK11_ReadAttribute(privk->pkcs11Slot,privk->pkcs11ID, + CKA_MODULUS,arena,&pubk->u.rsa.modulus); + if (rv != SECSuccess) break; + rv = PK11_ReadAttribute(privk->pkcs11Slot,privk->pkcs11ID, + CKA_PUBLIC_EXPONENT,arena,&pubk->u.rsa.publicExponent); + if (rv != SECSuccess) break; + return pubk; + break; + default: + break; + } + + PORT_FreeArena (arena, PR_FALSE); + return NULL; +} + +CERTSubjectPublicKeyInfo * +SECKEY_CreateSubjectPublicKeyInfo(SECKEYPublicKey *pubk) +{ + CERTSubjectPublicKeyInfo *spki; + PRArenaPool *arena; + SECItem params = { siBuffer, NULL, 0 }; + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + PORT_SetError(SEC_ERROR_NO_MEMORY); + return NULL; + } + + spki = (CERTSubjectPublicKeyInfo *) PORT_ArenaZAlloc(arena, sizeof (*spki)); + if (spki != NULL) { + SECStatus rv; + SECItem *rv_item; + + spki->arena = arena; + switch(pubk->keyType) { + case rsaKey: + rv = SECOID_SetAlgorithmID(arena, &spki->algorithm, + SEC_OID_PKCS1_RSA_ENCRYPTION, 0); + if (rv == SECSuccess) { + /* + * DER encode the public key into the subjectPublicKeyInfo. + */ + rv_item = SEC_ASN1EncodeItem(arena, &spki->subjectPublicKey, + pubk, SECKEY_RSAPublicKeyTemplate); + if (rv_item != NULL) { + /* + * The stored value is supposed to be a BIT_STRING, + * so convert the length. + */ + spki->subjectPublicKey.len <<= 3; + /* + * We got a good one; return it. + */ + return spki; + } + } + break; + case dsaKey: + /* DER encode the params. */ + rv_item = SEC_ASN1EncodeItem(arena, ¶ms, &pubk->u.dsa.params, + SECKEY_PQGParamsTemplate); + if (rv_item != NULL) { + rv = SECOID_SetAlgorithmID(arena, &spki->algorithm, + SEC_OID_ANSIX9_DSA_SIGNATURE, + ¶ms); + if (rv == SECSuccess) { + /* + * DER encode the public key into the subjectPublicKeyInfo. + */ + rv_item = SEC_ASN1EncodeItem(arena, &spki->subjectPublicKey, + pubk, + SECKEY_DSAPublicKeyTemplate); + if (rv_item != NULL) { + /* + * The stored value is supposed to be a BIT_STRING, + * so convert the length. + */ + spki->subjectPublicKey.len <<= 3; + /* + * We got a good one; return it. + */ + return spki; + } + } + } + SECITEM_FreeItem(¶ms, PR_FALSE); + break; + case keaKey: + case dhKey: /* later... */ + + break; + case fortezzaKey: +#ifdef notdef + /* encode the DSS parameters (PQG) */ + rv = FortezzaBuildParams(¶ms,pubk); + if (rv != SECSuccess) break; + + /* set the algorithm */ + rv = SECOID_SetAlgorithmID(arena, &spki->algorithm, + SEC_OID_MISSI_KEA_DSS, ¶ms); + PORT_Free(params.data); + if (rv == SECSuccess) { + /* + * Encode the public key into the subjectPublicKeyInfo. + * Fortezza key material is not standard DER + */ + rv = FortezzaEncodeCertKey(arena,&spki->subjectPublicKey,pubk); + if (rv == SECSuccess) { + /* + * The stored value is supposed to be a BIT_STRING, + * so convert the length. + */ + spki->subjectPublicKey.len <<= 3; + + /* + * We got a good one; return it. + */ + return spki; + } + } +#endif + break; + default: + break; + } + } else { + PORT_SetError(SEC_ERROR_NO_MEMORY); + } + + PORT_FreeArena(arena, PR_FALSE); + return NULL; +} + +void +SECKEY_DestroySubjectPublicKeyInfo(CERTSubjectPublicKeyInfo *spki) +{ + if (spki && spki->arena) { + PORT_FreeArena(spki->arena, PR_FALSE); + } +} + +/* + * this only works for RSA keys... need to do something + * similiar to CERT_ExtractPublicKey for other key times. + */ +SECKEYPublicKey * +SECKEY_DecodeDERPublicKey(SECItem *pubkder) +{ + PRArenaPool *arena; + SECKEYPublicKey *pubk; + SECStatus rv; + + arena = PORT_NewArena (DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + PORT_SetError (SEC_ERROR_NO_MEMORY); + return NULL; + } + + pubk = (SECKEYPublicKey *) PORT_ArenaZAlloc (arena, sizeof (SECKEYPublicKey)); + if (pubk != NULL) { + pubk->arena = arena; + pubk->pkcs11Slot = NULL; + pubk->pkcs11ID = 0; + rv = SEC_ASN1DecodeItem(arena, pubk, SECKEY_RSAPublicKeyTemplate, + pubkder); + if (rv == SECSuccess) + return pubk; + SECKEY_DestroyPublicKey (pubk); + } else { + PORT_SetError (SEC_ERROR_NO_MEMORY); + } + + PORT_FreeArena (arena, PR_FALSE); + return NULL; +} + +/* + * Decode a base64 ascii encoded DER encoded public key. + */ +SECKEYPublicKey * +SECKEY_ConvertAndDecodePublicKey(char *pubkstr) +{ + SECKEYPublicKey *pubk; + SECStatus rv; + SECItem der; + + rv = ATOB_ConvertAsciiToItem (&der, pubkstr); + if (rv != SECSuccess) + return NULL; + + pubk = SECKEY_DecodeDERPublicKey (&der); + + PORT_Free (der.data); + return pubk; +} + +CERTSubjectPublicKeyInfo * +SECKEY_DecodeDERSubjectPublicKeyInfo(SECItem *spkider) +{ + PRArenaPool *arena; + CERTSubjectPublicKeyInfo *spki; + SECStatus rv; + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + PORT_SetError(SEC_ERROR_NO_MEMORY); + return NULL; + } + + spki = (CERTSubjectPublicKeyInfo *) + PORT_ArenaZAlloc(arena, sizeof (CERTSubjectPublicKeyInfo)); + if (spki != NULL) { + spki->arena = arena; + rv = SEC_ASN1DecodeItem(arena,spki, + CERT_SubjectPublicKeyInfoTemplate,spkider); + if (rv == SECSuccess) + return spki; + SECKEY_DestroySubjectPublicKeyInfo(spki); + } else { + PORT_SetError(SEC_ERROR_NO_MEMORY); + } + + PORT_FreeArena(arena, PR_FALSE); + return NULL; +} + +/* + * Decode a base64 ascii encoded DER encoded subject public key info. + */ +CERTSubjectPublicKeyInfo * +SECKEY_ConvertAndDecodeSubjectPublicKeyInfo(char *spkistr) +{ + CERTSubjectPublicKeyInfo *spki; + SECStatus rv; + SECItem der; + + rv = ATOB_ConvertAsciiToItem(&der, spkistr); + if (rv != SECSuccess) + return NULL; + + spki = SECKEY_DecodeDERSubjectPublicKeyInfo(&der); + + PORT_Free(der.data); + return spki; +} + +/* + * Decode a base64 ascii encoded DER encoded public key and challenge + * Verify digital signature and make sure challenge matches + */ +CERTSubjectPublicKeyInfo * +SECKEY_ConvertAndDecodePublicKeyAndChallenge(char *pkacstr, char *challenge, + void *wincx) +{ + CERTSubjectPublicKeyInfo *spki = NULL; + CERTPublicKeyAndChallenge pkac; + SECStatus rv; + SECItem signedItem; + PRArenaPool *arena = NULL; + CERTSignedData sd; + SECItem sig; + SECKEYPublicKey *pubKey = NULL; + int len; + + signedItem.data = NULL; + + /* convert the base64 encoded data to binary */ + rv = ATOB_ConvertAsciiToItem(&signedItem, pkacstr); + if (rv != SECSuccess) { + goto loser; + } + + /* create an arena */ + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + goto loser; + } + + /* decode the outer wrapping of signed data */ + PORT_Memset(&sd, 0, sizeof(CERTSignedData)); + rv = SEC_ASN1DecodeItem(arena, &sd, CERT_SignedDataTemplate, &signedItem ); + if ( rv ) { + goto loser; + } + + /* decode the public key and challenge wrapper */ + PORT_Memset(&pkac, 0, sizeof(CERTPublicKeyAndChallenge)); + rv = SEC_ASN1DecodeItem(arena, &pkac, CERT_PublicKeyAndChallengeTemplate, + &sd.data); + if ( rv ) { + goto loser; + } + + /* decode the subject public key info */ + spki = SECKEY_DecodeDERSubjectPublicKeyInfo(&pkac.spki); + if ( spki == NULL ) { + goto loser; + } + + /* get the public key */ + pubKey = seckey_ExtractPublicKey(spki); + if ( pubKey == NULL ) { + goto loser; + } + + /* check the signature */ + sig = sd.signature; + DER_ConvertBitString(&sig); + rv = VFY_VerifyData(sd.data.data, sd.data.len, pubKey, &sig, + SECOID_GetAlgorithmTag(&(sd.signatureAlgorithm)), wincx); + if ( rv != SECSuccess ) { + goto loser; + } + + /* check the challenge */ + if ( challenge ) { + len = PORT_Strlen(challenge); + /* length is right */ + if ( len != pkac.challenge.len ) { + goto loser; + } + /* actual data is right */ + if ( PORT_Memcmp(challenge, pkac.challenge.data, len) != 0 ) { + goto loser; + } + } + goto done; + +loser: + /* make sure that we return null if we got an error */ + if ( spki ) { + SECKEY_DestroySubjectPublicKeyInfo(spki); + } + spki = NULL; + +done: + if ( signedItem.data ) { + PORT_Free(signedItem.data); + } + if ( arena ) { + PORT_FreeArena(arena, PR_FALSE); + } + if ( pubKey ) { + SECKEY_DestroyPublicKey(pubKey); + } + + return spki; +} + +void +SECKEY_DestroyPrivateKeyInfo(SECKEYPrivateKeyInfo *pvk, + PRBool freeit) +{ + PRArenaPool *poolp; + + if(pvk != NULL) { + if(pvk->arena) { + poolp = pvk->arena; + /* zero structure since PORT_FreeArena does not support + * this yet. + */ + PORT_Memset(pvk->privateKey.data, 0, pvk->privateKey.len); + PORT_Memset((char *)pvk, 0, sizeof(*pvk)); + if(freeit == PR_TRUE) { + PORT_FreeArena(poolp, PR_TRUE); + } else { + pvk->arena = poolp; + } + } else { + SECITEM_ZfreeItem(&pvk->version, PR_FALSE); + SECITEM_ZfreeItem(&pvk->privateKey, PR_FALSE); + SECOID_DestroyAlgorithmID(&pvk->algorithm, PR_FALSE); + PORT_Memset((char *)pvk, 0, sizeof(pvk)); + if(freeit == PR_TRUE) { + PORT_Free(pvk); + } + } + } +} + +void +SECKEY_DestroyEncryptedPrivateKeyInfo(SECKEYEncryptedPrivateKeyInfo *epki, + PRBool freeit) +{ + PRArenaPool *poolp; + + if(epki != NULL) { + if(epki->arena) { + poolp = epki->arena; + /* zero structure since PORT_FreeArena does not support + * this yet. + */ + PORT_Memset(epki->encryptedData.data, 0, epki->encryptedData.len); + PORT_Memset((char *)epki, 0, sizeof(*epki)); + if(freeit == PR_TRUE) { + PORT_FreeArena(poolp, PR_TRUE); + } else { + epki->arena = poolp; + } + } else { + SECITEM_ZfreeItem(&epki->encryptedData, PR_FALSE); + SECOID_DestroyAlgorithmID(&epki->algorithm, PR_FALSE); + PORT_Memset((char *)epki, 0, sizeof(epki)); + if(freeit == PR_TRUE) { + PORT_Free(epki); + } + } + } +} + +SECStatus +SECKEY_CopyPrivateKeyInfo(PRArenaPool *poolp, + SECKEYPrivateKeyInfo *to, + SECKEYPrivateKeyInfo *from) +{ + SECStatus rv = SECFailure; + + if((to == NULL) || (from == NULL)) { + return SECFailure; + } + + rv = SECOID_CopyAlgorithmID(poolp, &to->algorithm, &from->algorithm); + if(rv != SECSuccess) { + return SECFailure; + } + rv = SECITEM_CopyItem(poolp, &to->privateKey, &from->privateKey); + if(rv != SECSuccess) { + return SECFailure; + } + rv = SECITEM_CopyItem(poolp, &to->version, &from->version); + + return rv; +} + +SECStatus +SECKEY_CopyEncryptedPrivateKeyInfo(PRArenaPool *poolp, + SECKEYEncryptedPrivateKeyInfo *to, + SECKEYEncryptedPrivateKeyInfo *from) +{ + SECStatus rv = SECFailure; + + if((to == NULL) || (from == NULL)) { + return SECFailure; + } + + rv = SECOID_CopyAlgorithmID(poolp, &to->algorithm, &from->algorithm); + if(rv != SECSuccess) { + return SECFailure; + } + rv = SECITEM_CopyItem(poolp, &to->encryptedData, &from->encryptedData); + + return rv; +} + +KeyType +SECKEY_GetPrivateKeyType(SECKEYPrivateKey *privKey) +{ + return privKey->keyType; +} + +KeyType +SECKEY_GetPublicKeyType(SECKEYPublicKey *pubKey) +{ + return pubKey->keyType; +} diff --git a/security/nss/lib/cryptohi/secsign.c b/security/nss/lib/cryptohi/secsign.c new file mode 100644 index 000000000..35af3f701 --- /dev/null +++ b/security/nss/lib/cryptohi/secsign.c @@ -0,0 +1,497 @@ +/* + * Signature stuff. + * + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + * + * $Id$ + */ + +#include <stdio.h> +#include "cryptohi.h" +#include "sechash.h" +#include "secder.h" +#include "keyhi.h" +#include "secoid.h" +#include "secdig.h" +#include "pk11func.h" +#include "secerr.h" + +struct SGNContextStr { + SECOidTag signalg; + SECOidTag hashalg; + void *hashcx; + SECHashObject *hashobj; + SECKEYPrivateKey *key; +}; + +SGNContext * +SGN_NewContext(SECOidTag alg, SECKEYPrivateKey *key) +{ + SGNContext *cx; + SECOidTag hashalg, signalg; + KeyType keyType; + + /* OK, map a PKCS #7 hash and encrypt algorithm into + * a standard hashing algorithm. Why did we pass in the whole + * PKCS #7 algTag if we were just going to change here you might + * ask. Well the answer is for some cards we may have to do the + * hashing on card. It may not support CKM_RSA_PKCS sign algorithm, + * it may just support CKM_RSA_PKCS_WITH_SHA1 and/or CKM_RSA_PKCS_WITH_MD5. + */ + switch (alg) { + /* We probably shouldn't be generating MD2 signatures either */ + case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION: + hashalg = SEC_OID_MD2; + signalg = SEC_OID_PKCS1_RSA_ENCRYPTION; + keyType = rsaKey; + break; + case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION: + hashalg = SEC_OID_MD5; + signalg = SEC_OID_PKCS1_RSA_ENCRYPTION; + keyType = rsaKey; + break; + case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION: + case SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE: + hashalg = SEC_OID_SHA1; + signalg = SEC_OID_PKCS1_RSA_ENCRYPTION; + keyType = rsaKey; + break; + /* what about normal DSA? */ + case SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST: + case SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST: + hashalg = SEC_OID_SHA1; + signalg = SEC_OID_ANSIX9_DSA_SIGNATURE; + keyType = dsaKey; + break; + case SEC_OID_MISSI_DSS: + case SEC_OID_MISSI_KEA_DSS: + case SEC_OID_MISSI_KEA_DSS_OLD: + case SEC_OID_MISSI_DSS_OLD: + hashalg = SEC_OID_SHA1; + signalg = SEC_OID_MISSI_DSS; /* XXX Is there a better algid? */ + keyType = fortezzaKey; + break; + /* we don't implement MD4 hashes. + * we *CERTAINLY* don't want to sign one! */ + case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION: + default: + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return 0; + } + + /* verify our key type */ + if (key->keyType != keyType && + !((key->keyType == dsaKey) && (keyType == fortezzaKey)) && + !((key->keyType == fortezzaKey) && (keyType == dsaKey)) ) { + PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); + return 0; + } + + cx = (SGNContext*) PORT_ZAlloc(sizeof(SGNContext)); + if (cx) { + cx->hashalg = hashalg; + cx->signalg = signalg; + cx->key = key; + } + return cx; +} + +void +SGN_DestroyContext(SGNContext *cx, PRBool freeit) +{ + if (cx) { + if (cx->hashcx != NULL) { + (*cx->hashobj->destroy)(cx->hashcx, PR_TRUE); + cx->hashcx = NULL; + } + if (freeit) { + PORT_ZFree(cx, sizeof(SGNContext)); + } + } +} + +SECStatus +SGN_Begin(SGNContext *cx) +{ + if (cx->hashcx != NULL) { + (*cx->hashobj->destroy)(cx->hashcx, PR_TRUE); + cx->hashcx = NULL; + } + + switch (cx->hashalg) { + case SEC_OID_MD2: + cx->hashobj = &SECHashObjects[HASH_AlgMD2]; + break; + case SEC_OID_MD5: + cx->hashobj = &SECHashObjects[HASH_AlgMD5]; + break; + case SEC_OID_SHA1: + cx->hashobj = &SECHashObjects[HASH_AlgSHA1]; + break; + default: + PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); + return SECFailure; + } + + cx->hashcx = (*cx->hashobj->create)(); + if (cx->hashcx == NULL) + return SECFailure; + + (*cx->hashobj->begin)(cx->hashcx); + return SECSuccess; +} + +SECStatus +SGN_Update(SGNContext *cx, unsigned char *input, unsigned inputLen) +{ + if (cx->hashcx == NULL) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + (*cx->hashobj->update)(cx->hashcx, input, inputLen); + return SECSuccess; +} + +SECStatus +SGN_End(SGNContext *cx, SECItem *result) +{ + unsigned char digest[32]; + unsigned part1, signatureLen; + SECStatus rv; + SECItem digder, sigitem; + PRArenaPool *arena = 0; + SECKEYPrivateKey *privKey = cx->key; + SGNDigestInfo *di = 0; + + + result->data = 0; + digder.data = 0; + + /* Finish up digest function */ + if (cx->hashcx == NULL) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + (*cx->hashobj->end)(cx->hashcx, digest, &part1, sizeof(digest)); + + + if (privKey->keyType == rsaKey) { + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if ( !arena ) { + rv = SECFailure; + goto loser; + } + + /* Construct digest info */ + di = SGN_CreateDigestInfo(cx->hashalg, digest, part1); + if (!di) { + rv = SECFailure; + goto loser; + } + + /* Der encode the digest as a DigestInfo */ + rv = DER_Encode(arena, &digder, SGNDigestInfoTemplate, di); + if (rv != SECSuccess) { + goto loser; + } + } else { + digder.data = digest; + digder.len = part1; + } + + /* + ** Encrypt signature after constructing appropriate PKCS#1 signature + ** block + */ + signatureLen = PK11_SignatureLen(privKey); + sigitem.len = signatureLen; + sigitem.data = (unsigned char*) PORT_Alloc(signatureLen); + + if (sigitem.data == NULL) { + rv = SECFailure; + goto loser; + } + + rv = PK11_Sign(privKey, &sigitem, &digder); + if (rv != SECSuccess) { + PORT_Free(sigitem.data); + sigitem.data = NULL; + } + + if (cx->signalg == SEC_OID_ANSIX9_DSA_SIGNATURE) { + rv = DSAU_EncodeDerSig(result, &sigitem); + PORT_Free(sigitem.data); + if (rv != SECSuccess) + goto loser; + } else { + result->len = sigitem.len; + result->data = sigitem.data; + } + + loser: + SGN_DestroyDigestInfo(di); + if (arena != NULL) { + PORT_FreeArena(arena, PR_FALSE); + } + return rv; +} + +/************************************************************************/ + +/* +** Sign a block of data returning in result a bunch of bytes that are the +** signature. Returns zero on success, an error code on failure. +*/ +SECStatus +SEC_SignData(SECItem *res, unsigned char *buf, int len, + SECKEYPrivateKey *pk, SECOidTag algid) +{ + SECStatus rv; + SGNContext *sgn; + + + sgn = SGN_NewContext(algid, pk); + + if (sgn == NULL) + return SECFailure; + + rv = SGN_Begin(sgn); + if (rv != SECSuccess) + goto loser; + + rv = SGN_Update(sgn, buf, len); + if (rv != SECSuccess) + goto loser; + + rv = SGN_End(sgn, res); + + loser: + SGN_DestroyContext(sgn, PR_TRUE); + return rv; +} + +/* +** Sign the input file's contents returning in result a bunch of bytes +** that are the signature. Returns zero on success, an error code on +** failure. +*/ +SECStatus +SEC_SignFile(SECItem *result, FILE *input, + SECKEYPrivateKey *pk, SECOidTag algid) +{ + unsigned char buf[1024]; + SECStatus rv; + int nb; + SGNContext *sgn; + + sgn = SGN_NewContext(algid, pk); + if (sgn == NULL) + return SECFailure; + rv = SGN_Begin(sgn); + if (rv != SECSuccess) + goto loser; + + /* + ** Now feed the contents of the input file into the digest + ** algorithm, one chunk at a time, until we have exhausted the + ** input + */ + for (;;) { + if (feof(input)) break; + nb = fread(buf, 1, sizeof(buf), input); + if (nb == 0) { + if (ferror(input)) { + PORT_SetError(SEC_ERROR_IO); + rv = SECFailure; + goto loser; + } + break; + } + rv = SGN_Update(sgn, buf, nb); + if (rv != SECSuccess) + goto loser; + } + + /* Sign the digest */ + rv = SGN_End(sgn, result); + /* FALL THROUGH */ + + loser: + SGN_DestroyContext(sgn, PR_TRUE); + return rv; +} + +/************************************************************************/ + +DERTemplate CERTSignedDataTemplate[] = +{ + { DER_SEQUENCE, + 0, NULL, sizeof(CERTSignedData) }, + { DER_ANY, + offsetof(CERTSignedData,data), }, + { DER_INLINE, + offsetof(CERTSignedData,signatureAlgorithm), + SECAlgorithmIDTemplate, }, + { DER_BIT_STRING, + offsetof(CERTSignedData,signature), }, + { 0, } +}; + +const SEC_ASN1Template CERT_SignedDataTemplate[] = +{ + { SEC_ASN1_SEQUENCE, + 0, NULL, sizeof(CERTSignedData) }, + { SEC_ASN1_ANY, + offsetof(CERTSignedData,data), }, + { SEC_ASN1_INLINE, + offsetof(CERTSignedData,signatureAlgorithm), + SECOID_AlgorithmIDTemplate, }, + { SEC_ASN1_BIT_STRING, + offsetof(CERTSignedData,signature), }, + { 0, } +}; + +SECStatus +SEC_DerSignData(PRArenaPool *arena, SECItem *result, + unsigned char *buf, int len, SECKEYPrivateKey *pk, SECOidTag algID) +{ + SECItem it; + CERTSignedData sd; + SECStatus rv; + + it.data = 0; + + /* XXX We should probably have some asserts here to make sure the key type + * and algID match + */ + + if (algID == SEC_OID_UNKNOWN) { + switch(pk->keyType) { + case rsaKey: + algID = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION; + break; + case dsaKey: + algID = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST; + break; + default: + return SECFailure; + break; + } + } + + /* Sign input buffer */ + rv = SEC_SignData(&it, buf, len, pk, algID); + if (rv) goto loser; + + /* Fill out SignedData object */ + PORT_Memset(&sd, 0, sizeof(sd)); + sd.data.data = buf; + sd.data.len = len; + sd.signature.data = it.data; + sd.signature.len = it.len << 3; /* convert to bit string */ + rv = SECOID_SetAlgorithmID(arena, &sd.signatureAlgorithm, algID, 0); + if (rv) goto loser; + + /* DER encode the signed data object */ + rv = DER_Encode(arena, result, CERTSignedDataTemplate, &sd); + /* FALL THROUGH */ + + loser: + PORT_Free(it.data); + return rv; +} + +SECStatus +SGN_Digest(SECKEYPrivateKey *privKey, + SECOidTag algtag, SECItem *result, SECItem *digest) +{ + unsigned modulusLen; + SECStatus rv; + SECItem digder; + PRArenaPool *arena = 0; + SGNDigestInfo *di = 0; + + + result->data = 0; + + if (privKey->keyType == rsaKey) { + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if ( !arena ) { + rv = SECFailure; + goto loser; + } + + /* Construct digest info */ + di = SGN_CreateDigestInfo(algtag, digest->data, digest->len); + if (!di) { + rv = SECFailure; + goto loser; + } + + /* Der encode the digest as a DigestInfo */ + rv = DER_Encode(arena, &digder, SGNDigestInfoTemplate, di); + if (rv != SECSuccess) { + goto loser; + } + } else { + digder.data = digest->data; + digder.len = digest->len; + } + + /* + ** Encrypt signature after constructing appropriate PKCS#1 signature + ** block + */ + modulusLen = PK11_SignatureLen(privKey); + result->len = modulusLen; + result->data = (unsigned char*) PORT_Alloc(modulusLen); + + if (result->data == NULL) { + rv = SECFailure; + goto loser; + } + + rv = PK11_Sign(privKey, result, &digder); + if (rv != SECSuccess) { + PORT_Free(result->data); + result->data = NULL; + } + + loser: + SGN_DestroyDigestInfo(di); + if (arena != NULL) { + PORT_FreeArena(arena, PR_FALSE); + } + return rv; +} diff --git a/security/nss/lib/cryptohi/secvfy.c b/security/nss/lib/cryptohi/secvfy.c new file mode 100644 index 000000000..6bd3fdc2e --- /dev/null +++ b/security/nss/lib/cryptohi/secvfy.c @@ -0,0 +1,389 @@ +/* + * Verification stuff. + * + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + * + * $Id$ + */ + +#include <stdio.h> +#include "cryptohi.h" +#include "sechash.h" +#include "keyhi.h" +#include "secasn1.h" +#include "secoid.h" +#include "pk11func.h" +#include "secdig.h" +#include "secerr.h" + +/* +** Decrypt signature block using public key (in place) +** XXX this is assuming that the signature algorithm has WITH_RSA_ENCRYPTION +*/ +static SECStatus +DecryptSigBlock(int *tagp, unsigned char *digest, SECKEYPublicKey *key, + SECItem *sig, char *wincx) +{ + SGNDigestInfo *di = NULL; + unsigned char *dsig = NULL; + unsigned char *buf = NULL; + SECStatus rv; + SECOidTag tag; + SECItem it; + + if (key == NULL) goto loser; + + it.len = SECKEY_PublicKeyStrength(key); + if (!it.len) goto loser; + it.data = buf = (unsigned char *)PORT_Alloc(it.len); + if (!buf) goto loser; + + /* Decrypt signature block */ + dsig = (unsigned char*) PORT_Alloc(sig->len); + if (dsig == NULL) goto loser; + + /* decrypt the block */ + rv = PK11_VerifyRecover(key, sig, &it, wincx); + if (rv != SECSuccess) goto loser; + + di = SGN_DecodeDigestInfo(&it); + if (di == NULL) goto sigloser; + + /* + ** Finally we have the digest info; now we can extract the algorithm + ** ID and the signature block + */ + tag = SECOID_GetAlgorithmTag(&di->digestAlgorithm); + /* XXX Check that tag is an appropriate algorithm? */ + if (di->digest.len > 32) { + PORT_SetError(SEC_ERROR_OUTPUT_LEN); + goto loser; + } + PORT_Memcpy(digest, di->digest.data, di->digest.len); + *tagp = tag; + goto done; + + sigloser: + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); + + loser: + rv = SECFailure; + + done: + if (di != NULL) SGN_DestroyDigestInfo(di); + if (dsig != NULL) PORT_Free(dsig); + if (buf != NULL) PORT_Free(buf); + + return rv; +} + +typedef enum { VFY_RSA, VFY_DSA} VerifyType; + +struct VFYContextStr { + int alg; + VerifyType type; + SECKEYPublicKey *key; + /* digest holds the full dsa signature... 40 bytes */ + unsigned char digest[DSA_SIGNATURE_LEN]; + void * wincx; + void *hashcx; + SECHashObject *hashobj; +}; + +VFYContext * +VFY_CreateContext(SECKEYPublicKey *key, SECItem *sig, SECOidTag algid, + void *wincx) +{ + VFYContext *cx; + SECStatus rv; + SECItem *dsasig = NULL; + + cx = (VFYContext*) PORT_ZAlloc(sizeof(VFYContext)); + if (cx) { + cx->wincx = cx; + switch (key->keyType) { + case rsaKey: + cx->type = VFY_RSA; + cx->key = NULL; /* extra safety precautions */ + rv = DecryptSigBlock(&cx->alg, &cx->digest[0], key, sig, (char*)wincx); + break; + case fortezzaKey: + case dsaKey: + cx->type = VFY_DSA; + cx->alg = SEC_OID_SHA1; + cx->key = SECKEY_CopyPublicKey(key); + /* if this is a DER encoded signature, decode it first */ + if ((algid == SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST) || + (algid == SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST) || + (algid == SEC_OID_ANSIX9_DSA_SIGNATURE)) { + dsasig = DSAU_DecodeDerSig(sig); + if ((dsasig == NULL) || (dsasig->len != DSA_SIGNATURE_LEN)) { + goto loser; + } + PORT_Memcpy(&cx->digest[0], dsasig->data, dsasig->len); + } else { + if (sig->len != DSA_SIGNATURE_LEN) { + goto loser; + } + PORT_Memcpy(&cx->digest[0], sig->data, sig->len); + } + rv = SECSuccess; + break; + default: + rv = SECFailure; + break; + } + if (rv) goto loser; + switch (cx->alg) { + case SEC_OID_MD2: + case SEC_OID_MD5: + case SEC_OID_SHA1: + break; + default: + PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); + goto loser; + } + } + return cx; + + loser: + if (dsasig != NULL) + SECITEM_FreeItem(dsasig, PR_TRUE); + VFY_DestroyContext(cx, PR_TRUE); + return 0; +} + +void +VFY_DestroyContext(VFYContext *cx, PRBool freeit) +{ + if (cx) { + if (cx->hashcx != NULL) { + (*cx->hashobj->destroy)(cx->hashcx, PR_TRUE); + cx->hashcx = NULL; + } + if (cx->key) { + SECKEY_DestroyPublicKey(cx->key); + } + if (freeit) { + PORT_ZFree(cx, sizeof(VFYContext)); + } + } +} + +SECStatus +VFY_Begin(VFYContext *cx) +{ + if (cx->hashcx != NULL) { + (*cx->hashobj->destroy)(cx->hashcx, PR_TRUE); + cx->hashcx = NULL; + } + + switch (cx->alg) { + case SEC_OID_MD2: + cx->hashobj = &SECHashObjects[HASH_AlgMD2]; + break; + case SEC_OID_MD5: + cx->hashobj = &SECHashObjects[HASH_AlgMD5]; + break; + case SEC_OID_SHA1: + cx->hashobj = &SECHashObjects[HASH_AlgSHA1]; + break; + default: + PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); + return SECFailure; + } + + cx->hashcx = (*cx->hashobj->create)(); + if (cx->hashcx == NULL) + return SECFailure; + + (*cx->hashobj->begin)(cx->hashcx); + return SECSuccess; +} + +SECStatus +VFY_Update(VFYContext *cx, unsigned char *input, unsigned inputLen) +{ + if (cx->hashcx == NULL) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + (*cx->hashobj->update)(cx->hashcx, input, inputLen); + return SECSuccess; +} + +SECStatus +VFY_End(VFYContext *cx) +{ + unsigned char final[32]; + unsigned part; + SECItem hash,sig; + + if (cx->hashcx == NULL) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + (*cx->hashobj->end)(cx->hashcx, final, &part, sizeof(final)); + switch (cx->type) { + case VFY_DSA: + sig.data = cx->digest; + sig.len = DSA_SIGNATURE_LEN; /* magic size of dsa signature */ + hash.data = final; + hash.len = part; + if (PK11_Verify(cx->key,&sig,&hash,cx->wincx) != SECSuccess) { + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); + return SECFailure; + } + break; + case VFY_RSA: + if (PORT_Memcmp(final, cx->digest, part)) { + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); + return SECFailure; + } + break; + default: + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); + return SECFailure; /* shouldn't happen */ + } + return SECSuccess; +} + +/************************************************************************/ +/* + * Verify that a previously-computed digest matches a signature. + * XXX This should take a parameter that specifies the digest algorithm, + * and we should compare that the algorithm found in the DigestInfo + * matches it! + */ +SECStatus +VFY_VerifyDigest(SECItem *digest, SECKEYPublicKey *key, SECItem *sig, + SECOidTag algid, void *wincx) +{ + SECStatus rv; + VFYContext *cx; + + rv = SECFailure; + + cx = VFY_CreateContext(key, sig, algid, wincx); + if (cx != NULL) { + switch (key->keyType) { + case rsaKey: + if (PORT_Memcmp(digest->data, cx->digest, digest->len)) { + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); + } else { + rv = SECSuccess; + } + break; + case fortezzaKey: + case dsaKey: + if (PK11_Verify(cx->key,sig,digest,wincx) != SECSuccess) { + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); + } else { + rv = SECSuccess; + } + break; + default: + break; + } + + VFY_DestroyContext(cx, PR_TRUE); + } + return rv; +} + +SECStatus +VFY_VerifyData(unsigned char *buf, int len, SECKEYPublicKey *key, + SECItem *sig, SECOidTag algid, void *wincx) +{ + SECStatus rv; + VFYContext *cx; + + cx = VFY_CreateContext(key, sig, algid, wincx); + if (cx == NULL) + return SECFailure; + + rv = VFY_Begin(cx); + if (rv == SECSuccess) { + rv = VFY_Update(cx, buf, len); + if (rv == SECSuccess) + rv = VFY_End(cx); + } + + VFY_DestroyContext(cx, PR_TRUE); + return rv; +} + +SECStatus +SEC_VerifyFile(FILE *input, SECKEYPublicKey *key, SECItem *sig, + SECOidTag algid, void *wincx) +{ + unsigned char buf[1024]; + SECStatus rv; + int nb; + VFYContext *cx; + + cx = VFY_CreateContext(key, sig, algid, wincx); + if (cx == NULL) + rv = SECFailure; + + rv = VFY_Begin(cx); + if (rv == SECSuccess) { + /* + * Now feed the contents of the input file into the digest algorithm, + * one chunk at a time, until we have exhausted the input. + */ + for (;;) { + if (feof(input)) + break; + nb = fread(buf, 1, sizeof(buf), input); + if (nb == 0) { + if (ferror(input)) { + PORT_SetError(SEC_ERROR_IO); + VFY_DestroyContext(cx, PR_TRUE); + return SECFailure; + } + break; + } + rv = VFY_Update(cx, buf, nb); + if (rv != SECSuccess) + goto loser; + } + } + + /* Verify the digest */ + rv = VFY_End(cx); + /* FALL THROUGH */ + + loser: + VFY_DestroyContext(cx, PR_TRUE); + return rv; +} |