/* * Copyright (c) 2003,2011-2012,2014 Apple Inc. All Rights Reserved. * * The contents of this file constitute Original Code as defined in and are * subject to the Apple Public Source License Version 1.2 (the 'License'). * You may not use this file except in compliance with the License. Please obtain * a copy of the License at http://www.apple.com/publicsource and read it before * using this file. * * This Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the * specific language governing rights and limitations under the License. */ /* * opensslAsn1.h - ANS1 encode/decode of openssl object, libssnasn1 version */ #include "opensslAsn1.h" #include "BinaryKey.h" #include "AppleCSPUtils.h" #include "opensshCoding.h" #include #include #include #include #include #include #include #include #include #include #include #define sslAsn1Debug(args...) secdebug("sslAsn1", ##args) #ifndef NDEBUG /* set to 1 to see all ASN related errors */ #define LOG_ASN_ERRORS 0 #else #define LOG_ASN_ERRORS 0 #endif #if LOG_ASN_ERRORS #include #include static void logAsnErr( const char *op, PRErrorCode perr) { printf("Error on %s: %s\n", op, SECErrorString(perr)); } #else #define logAsnErr(op, perr) #endif /* LOG_ASN_ERRORS */ /* CSSM_DATA --> BIGNUM */ BIGNUM *cssmDataToBn( const CSSM_DATA &cdata) { BIGNUM *bn = BN_new(); BIGNUM *rtn; rtn = BN_bin2bn(cdata.Data, (int)cdata.Length, bn); if(rtn == NULL) { BN_free(bn); CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR); } return bn; } /* BIGNUM --> CSSM_DATA, mallocing from a SecNssCoder's PL_ArenaPool */ void bnToCssmData( const BIGNUM *bn, CSSM_DATA &cdata, SecNssCoder &coder) { assert(bn != NULL); unsigned numBytes = BN_num_bytes(bn); cdata.Data = (uint8 *)coder.malloc(numBytes); if(cdata.Data == NULL) { CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR); } cdata.Length = numBytes; BN_bn2bin(bn, cdata.Data); } /* * CSSM_DATA --> unsigned int */ unsigned cssmDataToInt( const CSSM_DATA &cdata) { if((cdata.Length == 0) || (cdata.Data == NULL)) { return 0; } unsigned len = (unsigned)cdata.Length; if(len > sizeof(int)) { logAsnErr("cssmDataToInt: Length error (%u)", len); CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_ALG_PARAMS); } unsigned rtn = 0; uint8 *cp = cdata.Data; for(unsigned i=0; i CSSM_DATA, mallocing from an SecNssCoder */ void intToCssmData( unsigned num, CSSM_DATA &cdata, SecNssCoder &coder) { unsigned len = 0; if(num < 0x100) { len = 1; } else if(num < 0x10000) { len = 2; } else if(num < 0x1000000) { len = 3; } else { len = 4; } cdata.Data = (uint8 *)coder.malloc(len); cdata.Length = len; uint8 *cp = &cdata.Data[len - 1]; for(unsigned i=0; i>= 8; } } /* * Set up a encoded NULL for AlgorithmIdentifier.parameters, * required for RSA */ static void nullAlgParams( CSSM_X509_ALGORITHM_IDENTIFIER &algId) { static const uint8 encNull[2] = { SEC_ASN1_NULL, 0 }; CSSM_DATA encNullData; encNullData.Data = (uint8 *)encNull; encNullData.Length = 2; algId.parameters = encNullData; } #pragma mark - #pragma mark *** RSA key encode/decode *** /* * DER encode/decode RSA keys in various formats. * * Public key, CSSM_KEYBLOB_RAW_FORMAT_PKCS1 * -- compatible with BSAFE * -- used for CSSM_KEYBLOB_RAW_FORMAT_DIGEST on both keys */ static CSSM_RETURN RSAPublicKeyDecodePKCS1( SecNssCoder &coder, RSA *openKey, void *p, size_t length) { NSS_RSAPublicKeyPKCS1 nssPubKey; memset(&nssPubKey, 0, sizeof(nssPubKey)); PRErrorCode perr = coder.decode(p, length, kSecAsn1RSAPublicKeyPKCS1Template, &nssPubKey); if(perr) { logAsnErr("decode(RSAPublicKeyPKCS1)", perr); return CSSMERR_CSP_INVALID_KEY; } try { openKey->n = cssmDataToBn(nssPubKey.modulus); openKey->e = cssmDataToBn(nssPubKey.publicExponent); } catch(...) { return CSSMERR_CSP_MEMORY_ERROR; } return 0; } static CSSM_RETURN RSAPublicKeyEncodePKCS1( SecNssCoder &coder, RSA *openKey, CssmOwnedData &encodedKey) { /* convert to NSS_RSAPublicKeyPKCS1 */ NSS_RSAPublicKeyPKCS1 nssPubKey; try { bnToCssmData(openKey->n, nssPubKey.modulus, coder); bnToCssmData(openKey->e, nssPubKey.publicExponent, coder); } catch(...) { return CSSMERR_CSP_MEMORY_ERROR; } PRErrorCode prtn; prtn = SecNssEncodeItemOdata(&nssPubKey, kSecAsn1RSAPublicKeyPKCS1Template, encodedKey); if(prtn) { return CSSMERR_CSP_MEMORY_ERROR; } return CSSM_OK; } /* * SubjectPublicKeyInfo, as used by openssl. * The subjectPublicKey component is a PKCS1-style RSAPublicKey. */ static CSSM_RETURN RSAPublicKeyDecodeX509( SecNssCoder &coder, RSA *openKey, void *p, CSSM_SIZE length, /* mallocd/returned encoded alg params for OAEP key */ uint8 **algParams, CSSM_SIZE *algParamLen) { CSSM_X509_SUBJECT_PUBLIC_KEY_INFO nssPubKeyInfo; PRErrorCode perr; memset(&nssPubKeyInfo, 0, sizeof(nssPubKeyInfo)); perr = coder.decode(p, length, kSecAsn1SubjectPublicKeyInfoTemplate, &nssPubKeyInfo); if(perr) { logAsnErr("decode(RSA SubjectPublicKeyInfo)", perr); return CSSMERR_CSP_INVALID_KEY; } /* verify alg identifier */ const CSSM_OID *oid = &nssPubKeyInfo.algorithm.algorithm; if(!cspCompareCssmData(oid, &CSSMOID_RSA)) { if(!cspCompareCssmData(oid, &CSSMOID_RSAWithOAEP)) { sslAsn1Debug("RSAPublicKeyDecodeX509: bad OID"); return CSSMERR_CSP_INVALID_KEY; } if(nssPubKeyInfo.algorithm.parameters.Data != NULL) { CSSM_SIZE len = nssPubKeyInfo.algorithm.parameters.Length; *algParams = (uint8 *)malloc(len); memmove(*algParams, nssPubKeyInfo.algorithm.parameters.Data, len); *algParamLen = len; } } /* decode the raw bits */ CSSM_DATA *pubKey = &nssPubKeyInfo.subjectPublicKey; /* decoded length was in bits */ pubKey->Length = (pubKey->Length + 7) / 8; return RSAPublicKeyDecodePKCS1(coder, openKey, pubKey->Data, pubKey->Length); } static CSSM_RETURN RSAPublicKeyEncodeX509( SecNssCoder &coder, RSA *openKey, CssmOwnedData &encodedKey, /* encoded alg params for OAEP key */ uint8 *algParams, uint32 algParamsLen) { CssmAutoData aData(Allocator::standard()); CSSM_RETURN crtn; /* First get an encoded PKCS1-style RSAPublicKey */ crtn = RSAPublicKeyEncodePKCS1(coder, openKey, aData); if(crtn) { return crtn; } /* * That's the AsnBits subjectPublicKey component of a * SubjectPublicKeyInfo */ CSSM_X509_SUBJECT_PUBLIC_KEY_INFO nssPubKeyInfo; memset(&nssPubKeyInfo, 0, sizeof(nssPubKeyInfo)); nssPubKeyInfo.subjectPublicKey.Data = (uint8 *)aData.data(); nssPubKeyInfo.subjectPublicKey.Length = aData.length() * 8; CSSM_X509_ALGORITHM_IDENTIFIER &algId = nssPubKeyInfo.algorithm; algId.algorithm = CSSMOID_RSA; if(algParams) { algId.parameters.Data = (uint8 *)algParams; algId.parameters.Length = algParamsLen; } else { /* NULL algorithm parameters */ nullAlgParams(algId); } /* DER encode */ PRErrorCode perr; perr = SecNssEncodeItemOdata(&nssPubKeyInfo, kSecAsn1SubjectPublicKeyInfoTemplate, encodedKey); if(perr) { logAsnErr("encode(RSA SubjectPublicKeyInfo)", perr); return CSSMERR_CSP_MEMORY_ERROR; } return CSSM_OK; } /* * RSA private key, PKCS1 format, used by openssl. */ static CSSM_RETURN RSAPrivateKeyDecodePKCS1( SecNssCoder &coder, RSA *openKey, void *p, size_t length) { NSS_RSAPrivateKeyPKCS1 nssPrivKey; PRErrorCode perr; memset(&nssPrivKey, 0, sizeof(nssPrivKey)); perr = coder.decode(p, length, kSecAsn1RSAPrivateKeyPKCS1Template, &nssPrivKey); if(perr) { logAsnErr("decode(RSAPrivateKeyPKCS)", perr); return CSSMERR_CSP_INVALID_KEY; } /* convert nssPrivKey fields to RSA key fields */ try { openKey->version = cssmDataToInt(nssPrivKey.version); openKey->n = cssmDataToBn(nssPrivKey.modulus); openKey->e = cssmDataToBn(nssPrivKey.publicExponent); openKey->d = cssmDataToBn(nssPrivKey.privateExponent); openKey->p = cssmDataToBn(nssPrivKey.prime1); openKey->q = cssmDataToBn(nssPrivKey.prime2); openKey->dmp1 = cssmDataToBn(nssPrivKey.exponent1); openKey->dmq1 = cssmDataToBn(nssPrivKey.exponent2); openKey->iqmp = cssmDataToBn(nssPrivKey.coefficient); } catch(...) { return CSSMERR_CSP_MEMORY_ERROR; } return 0; } static CSSM_RETURN RSAPrivateKeyEncodePKCS1( SecNssCoder &coder, RSA *openKey, CssmOwnedData &encodedKey) { NSS_RSAPrivateKeyPKCS1 nssPrivKey; PRErrorCode perr; /* convert to NSS_RSAPrivateKeyPKCS1 */ try { intToCssmData(openKey->version, nssPrivKey.version, coder); bnToCssmData(openKey->n, nssPrivKey.modulus, coder); bnToCssmData(openKey->e, nssPrivKey.publicExponent, coder); bnToCssmData(openKey->d, nssPrivKey.privateExponent, coder); bnToCssmData(openKey->p, nssPrivKey.prime1, coder); bnToCssmData(openKey->q, nssPrivKey.prime2, coder); bnToCssmData(openKey->dmp1, nssPrivKey.exponent1, coder); bnToCssmData(openKey->dmq1, nssPrivKey.exponent2, coder); bnToCssmData(openKey->iqmp, nssPrivKey.coefficient, coder); } catch(...) { /* ? */ return CSSMERR_CSP_MEMORY_ERROR; } /* DER encode */ perr = SecNssEncodeItemOdata(&nssPrivKey, kSecAsn1RSAPrivateKeyPKCS1Template, encodedKey); if(perr) { logAsnErr("encode(RSAPrivateKeyPKCS1)", perr); return CSSMERR_CSP_MEMORY_ERROR; } return CSSM_OK; } /* * RSA private key, PKCS8, compatible with BSAFE. */ static CSSM_RETURN RSAPrivateKeyDecodePKCS8( SecNssCoder &coder, RSA *openKey, void *p, CSSM_SIZE length, /* mallocd/returned encoded alg params for OAEP key */ uint8 **algParams, CSSM_SIZE *algParamLen) { NSS_PrivateKeyInfo nssPrivKeyInfo; PRErrorCode perr; memset(&nssPrivKeyInfo, 0, sizeof(nssPrivKeyInfo)); perr = coder.decode(p, length, kSecAsn1PrivateKeyInfoTemplate, &nssPrivKeyInfo); if(perr) { logAsnErr("decode(PrivateKeyInfo)", perr); return CSSMERR_CSP_INVALID_KEY; } /* verify alg identifier */ const CSSM_OID *oid = &nssPrivKeyInfo.algorithm.algorithm; if(!cspCompareCssmData(oid, &CSSMOID_RSA)) { if(!cspCompareCssmData(oid, &CSSMOID_RSAWithOAEP)) { sslAsn1Debug("RSAPrivateKeyDecodePKCS8: bad OID"); return CSSMERR_CSP_INVALID_KEY; } if(nssPrivKeyInfo.algorithm.parameters.Data != NULL) { CSSM_SIZE len = nssPrivKeyInfo.algorithm.parameters.Length; *algParams = (uint8 *)malloc(len); memmove(*algParams, nssPrivKeyInfo.algorithm.parameters.Data, len); *algParamLen = len; } } /* * nssPrivKeyInfo.privateKey is an octet string which needs * subsequent decoding */ CSSM_DATA *privKey = &nssPrivKeyInfo.privateKey; return RSAPrivateKeyDecodePKCS1(coder, openKey, privKey->Data, privKey->Length); } static CSSM_RETURN RSAPrivateKeyEncodePKCS8( SecNssCoder &coder, RSA *openKey, CssmOwnedData &encodedKey, /* encoded alg params for OAEP key */ uint8 *algParams, uint32 algParamsLen) { /* First get PKCS1-style encoding */ CssmAutoData aData(Allocator::standard()); CSSM_RETURN crtn = RSAPrivateKeyEncodePKCS1(coder, openKey, aData); if(crtn) { return crtn; } /* that encoding is the privateKey field of a NSS_PrivateKeyInfo */ NSS_PrivateKeyInfo nssPrivKeyInfo; memset(&nssPrivKeyInfo, 0, sizeof(nssPrivKeyInfo)); nssPrivKeyInfo.privateKey.Data = (uint8 *)aData.data(); nssPrivKeyInfo.privateKey.Length = aData.length(); CSSM_X509_ALGORITHM_IDENTIFIER &algId = nssPrivKeyInfo.algorithm; algId.algorithm = CSSMOID_RSA; if(algParams) { algId.parameters.Data = (uint8 *)algParams; algId.parameters.Length = algParamsLen; } else { /* NULL algorithm parameters */ nullAlgParams(algId); } /* FIXME : attributes? */ uint8 vers = 0; nssPrivKeyInfo.version.Data = &vers; nssPrivKeyInfo.version.Length = 1; /* DER encode */ PRErrorCode perr; perr = SecNssEncodeItemOdata(&nssPrivKeyInfo, kSecAsn1PrivateKeyInfoTemplate, encodedKey); if(perr) { logAsnErr("encode(RSA PrivateKeyInfo)", perr); return CSSMERR_CSP_MEMORY_ERROR; } return CSSM_OK; } CSSM_RETURN RSAPublicKeyDecode( RSA *openKey, CSSM_KEYBLOB_FORMAT format, void *p, size_t length) { SecNssCoder coder; switch(format) { case CSSM_KEYBLOB_RAW_FORMAT_PKCS1: return RSAPublicKeyDecodePKCS1(coder, openKey, p, length); case CSSM_KEYBLOB_RAW_FORMAT_X509: return RSAPublicKeyDecodeX509(coder, openKey, p, length, NULL, NULL); case CSSM_KEYBLOB_RAW_FORMAT_OPENSSH: return RSAPublicKeyDecodeOpenSSH1(openKey, p, length); case CSSM_KEYBLOB_RAW_FORMAT_OPENSSH2: return RSAPublicKeyDecodeOpenSSH2(openKey, p, length); default: assert(0); return CSSMERR_CSP_INTERNAL_ERROR; } } CSSM_RETURN RSAPublicKeyEncode( RSA *openKey, CSSM_KEYBLOB_FORMAT format, const CssmData &descData, CssmOwnedData &encodedKey) { SecNssCoder coder; switch(format) { case CSSM_KEYBLOB_RAW_FORMAT_PKCS1: return RSAPublicKeyEncodePKCS1(coder, openKey, encodedKey); case CSSM_KEYBLOB_RAW_FORMAT_X509: return RSAPublicKeyEncodeX509(coder, openKey, encodedKey, NULL, 0); case CSSM_KEYBLOB_RAW_FORMAT_OPENSSH: return RSAPublicKeyEncodeOpenSSH1(openKey, descData, encodedKey); case CSSM_KEYBLOB_RAW_FORMAT_OPENSSH2: return RSAPublicKeyEncodeOpenSSH2(openKey, descData, encodedKey); default: assert(0); return CSSMERR_CSP_INTERNAL_ERROR; } } CSSM_RETURN RSAPrivateKeyDecode( RSA *openKey, CSSM_KEYBLOB_FORMAT format, void *p, size_t length) { SecNssCoder coder; switch(format) { case CSSM_KEYBLOB_RAW_FORMAT_PKCS1: return RSAPrivateKeyDecodePKCS1(coder, openKey, p, length); case CSSM_KEYBLOB_RAW_FORMAT_PKCS8: return RSAPrivateKeyDecodePKCS8(coder, openKey, p, length, NULL, NULL); case CSSM_KEYBLOB_RAW_FORMAT_OPENSSH: return RSAPrivateKeyDecodeOpenSSH1(openKey, p, length); default: assert(0); return CSSMERR_CSP_INTERNAL_ERROR; } } CSSM_RETURN RSAPrivateKeyEncode( RSA *openKey, CSSM_KEYBLOB_FORMAT format, const CssmData &descData, CssmOwnedData &encodedKey) { SecNssCoder coder; switch(format) { case CSSM_KEYBLOB_RAW_FORMAT_PKCS1: return RSAPrivateKeyEncodePKCS1(coder, openKey, encodedKey); case CSSM_KEYBLOB_RAW_FORMAT_PKCS8: return RSAPrivateKeyEncodePKCS8(coder, openKey, encodedKey, NULL, 0); case CSSM_KEYBLOB_RAW_FORMAT_OPENSSH: return RSAPrivateKeyEncodeOpenSSH1(openKey, descData, encodedKey); default: assert(0); return CSSMERR_CSP_INTERNAL_ERROR; } } CSSM_RETURN RSAOAEPPrivateKeyEncode( RSA *openKey, const CSSM_DATA *label, CssmOwnedData &encodedKey) { SecNssCoder coder; CSSM_DATA encodedParams = {0, NULL}; /* TBD encode the label into a RSAES-OAEP-params */ return RSAPrivateKeyEncodePKCS8(coder, openKey, encodedKey, encodedParams.Data, (unsigned int)encodedParams.Length); } CSSM_RETURN RSAOAEPPublicKeyEncode( RSA *openKey, const CSSM_DATA *label, CssmOwnedData &encodedKey) { SecNssCoder coder; CSSM_DATA encodedParams = {0, NULL}; /* TBD encode the label into a RSAES-OAEP-params */ return RSAPublicKeyEncodeX509(coder, openKey, encodedKey, encodedParams.Data, (unsigned int)encodedParams.Length); } CSSM_RETURN RSAOAEPPublicKeyDecode( RSA *openKey, void *p, size_t length, /* mallocd and returned label */ CSSM_DATA *label) { SecNssCoder coder; CSSM_RETURN crtn; CSSM_DATA encodedParams = {0, NULL}; crtn = RSAPublicKeyDecodeX509(coder, openKey, p, length, &encodedParams.Data, &encodedParams.Length); if(crtn) { return crtn; } /* TBD - decode label from encoded alg params */ label->Data = NULL; label->Length = 0; return CSSM_OK; } CSSM_RETURN RSAOAEPPrivateKeyDecode( RSA *openKey, void *p, size_t length, /* mallocd and returned label */ CSSM_DATA *label) { SecNssCoder coder; CSSM_RETURN crtn; CSSM_DATA encodedParams = {0, NULL}; crtn = RSAPrivateKeyDecodePKCS8(coder, openKey, p, length, &encodedParams.Data, &encodedParams.Length); if(crtn) { return crtn; } /* TBD - decode label from encoded alg params */ label->Data = NULL; label->Length = 0; return CSSM_OK; } #pragma mark - #pragma mark *** DSA key encode/decode *** /*** *** DSA ***/ /* NSS_DSAAlgorithmIdBSAFE <--> DSA->{p,g,q} */ static void dsaToNssAlgIdBSAFE( const DSA *openKey, NSS_DSAAlgorithmIdBSAFE &algId, SecNssCoder &coder) { /* non-standard, BSAFE-specific OID */ algId.algorithm = CSSMOID_DSA; // not mallocd unsigned numBits = BN_num_bits(openKey->p); intToCssmData(numBits, algId.params.keySizeInBits, coder); bnToCssmData(openKey->p, algId.params.p, coder); bnToCssmData(openKey->q, algId.params.q, coder); bnToCssmData(openKey->g, algId.params.g, coder); } static CSSM_RETURN nssAlgIdToDsaBSAFE( NSS_DSAAlgorithmIdBSAFE &algId, DSA *openKey) { /* non-standard, BSAFE-specific OID */ if(!cspCompareCssmData(&algId.algorithm, &CSSMOID_DSA)) { sslAsn1Debug("nssAlgIdToDsaBSAFE: bad OID"); return CSSMERR_CSP_INVALID_KEY; } openKey->p = cssmDataToBn(algId.params.p); openKey->q = cssmDataToBn(algId.params.q); openKey->g = cssmDataToBn(algId.params.g); return CSSM_OK; } /* NSS_DSAAlgorithmIdX509 <--> DSA->{p,g,q} */ static void dsaToNssAlgIdX509( const DSA *openKey, NSS_DSAAlgorithmIdX509 &algId, SecNssCoder &coder) { algId.algorithm = CSSMOID_DSA_CMS; // not mallocd bnToCssmData(openKey->p, algId.params->p, coder); bnToCssmData(openKey->q, algId.params->q, coder); bnToCssmData(openKey->g, algId.params->g, coder); } static CSSM_RETURN nssAlgIdToDsaX509( NSS_DSAAlgorithmIdX509 &algId, DSA *openKey) { if(!cspCompareCssmData(&algId.algorithm, &CSSMOID_DSA_CMS) && !cspCompareCssmData(&algId.algorithm, &CSSMOID_DSA_JDK)) { sslAsn1Debug("nssAlgIdToDsaX509: bad OID"); return CSSMERR_CSP_INVALID_KEY; } /* these might be absent per CMS */ if(algId.params == NULL) { return CSSM_OK; } openKey->p = cssmDataToBn(algId.params->p); openKey->q = cssmDataToBn(algId.params->q); openKey->g = cssmDataToBn(algId.params->g); return CSSM_OK; } /* * DSA public keys, FIPS186 format. * Compatible with BSAFE. */ static CSSM_RETURN DSAPublicKeyDecodeFIPS186( SecNssCoder &coder, DSA *openKey, void *p, size_t length) { NSS_DSAPublicKeyBSAFE nssPubKey; PRErrorCode perr; CSSM_RETURN crtn; memset(&nssPubKey, 0, sizeof(nssPubKey)); perr = coder.decode(p, length, kSecAsn1DSAPublicKeyBSAFETemplate, &nssPubKey); if(perr) { logAsnErr("decode(DSAPublicKeyBSAFE)", perr); return CSSMERR_CSP_INVALID_KEY; } /* BSAFE style DSA-specific alg params */ NSS_DSAAlgorithmIdBSAFE &algId = nssPubKey.dsaAlg; crtn = nssAlgIdToDsaBSAFE(algId, openKey); if(crtn) { return crtn; } /* inside of nssPubKey.publicKey is the DER-encoding of a * ASN Integer; decoded length was in bits */ nssPubKey.publicKey.Length = (nssPubKey.publicKey.Length + 7) / 8; CSSM_DATA pubKeyBytes; perr = coder.decodeItem(nssPubKey.publicKey, kSecAsn1UnsignedIntegerTemplate, &pubKeyBytes); if(perr) { logAsnErr("decode(NSS_DSAPublicKeyBSAFE.publicKey)", perr); return CSSMERR_CSP_INVALID_KEY; } openKey->pub_key = cssmDataToBn(pubKeyBytes); if(openKey->pub_key == NULL) { return CSSMERR_CSP_INVALID_KEY; } return 0; } static CSSM_RETURN DSAPublicKeyEncodeFIPS186( SecNssCoder &coder, DSA *openKey, CssmOwnedData &encodedKey) { try { /* convert to NSS_DSAPublicKeyBSAFE */ NSS_DSAPublicKeyBSAFE nssPubKey; memset(&nssPubKey, 0, sizeof(nssPubKey)); dsaToNssAlgIdBSAFE(openKey, nssPubKey.dsaAlg, coder); /* * publicKey is the DER-encoding of a ASN INTEGER wrapped in * an AsnBits */ CSSM_DATA pubKeyRaw; PRErrorCode perr; bnToCssmData(openKey->pub_key, pubKeyRaw, coder); perr = coder.encodeItem(&pubKeyRaw, kSecAsn1UnsignedIntegerTemplate, nssPubKey.publicKey); if(perr) { logAsnErr("encodeItem(DSAPublicKeyBSAFE.publicKey)", perr); return CSSMERR_CSP_MEMORY_ERROR; } nssPubKey.publicKey.Length *= 8; /* DER encode */ SecNssEncodeItemOdata(&nssPubKey, kSecAsn1DSAPublicKeyBSAFETemplate, encodedKey); return CSSM_OK; } catch(...) { /* ? */ return CSSMERR_CSP_MEMORY_ERROR; } } /* * DSA private keys, FIPS186 format. * Compatible with BSAFE. */ static CSSM_RETURN DSAPrivateKeyDecodeFIPS186( SecNssCoder &coder, DSA *openKey, void *p, unsigned length) { NSS_DSAPrivateKeyBSAFE nssPrivKeyInfo; PRErrorCode perr; memset(&nssPrivKeyInfo, 0, sizeof(nssPrivKeyInfo)); perr = coder.decode(p, length, kSecAsn1DSAPrivateKeyBSAFETemplate, &nssPrivKeyInfo); if(perr) { logAsnErr("decode(DSA PrivateKeyInfo)", perr); return CSSMERR_CSP_INVALID_KEY; } CSSM_RETURN crtn = nssAlgIdToDsaBSAFE(nssPrivKeyInfo.dsaAlg, openKey); if(crtn) { return crtn; } /* nssPrivKeyInfo.privateKey is the DER-encoding of a * DSAPrivateKeyOcts... */ try { PRErrorCode perr; NSS_DSAPrivateKeyOcts keyOcts; perr = coder.decodeItem(nssPrivKeyInfo.privateKey, kSecAsn1DSAPrivateKeyOctsTemplate, &keyOcts); if(perr) { logAsnErr("decode(DSA PrivateKeyInfoOcts)", perr); return CSSMERR_CSP_INVALID_KEY; } openKey->priv_key = cssmDataToBn(keyOcts.privateKey); if(openKey->priv_key == NULL) { return CSSMERR_CSP_INVALID_KEY; } return 0; } catch(...) { return CSSMERR_CSP_INVALID_KEY; } } static CSSM_RETURN DSAPrivateKeyEncodeFIPS186( SecNssCoder &coder, DSA *openKey, CssmOwnedData &encodedKey) { try { /* First convert into a NSS_DSAPrivateKeyBSAFE */ NSS_DSAPrivateKeyBSAFE nssPrivKey; intToCssmData(openKey->version, nssPrivKey.version, coder); dsaToNssAlgIdBSAFE(openKey, nssPrivKey.dsaAlg, coder); /* nssPrivKey.privateKey is the DER-encoding of one of these... */ NSS_DSAPrivateKeyOcts privKeyOcts; bnToCssmData(openKey->priv_key, privKeyOcts.privateKey, coder); /* DER encode the privateKey portion into arena pool memory * into NSS_DSAPrivateKeyPKCS8.privateKey */ coder.encodeItem(&privKeyOcts, kSecAsn1DSAPrivateKeyOctsTemplate, nssPrivKey.privateKey); /* DER encode the whole thing */ PRErrorCode perr; perr = SecNssEncodeItemOdata(&nssPrivKey, kSecAsn1DSAPrivateKeyBSAFETemplate, encodedKey); return 0; } catch(...) { /* ? */ return CSSMERR_CSP_MEMORY_ERROR; } } /* * DSA private keys, PKCS8/SMIME format. */ static CSSM_RETURN DSAPrivateKeyDecodePKCS8( SecNssCoder &coder, DSA *openKey, void *p, unsigned length) { NSS_DSAPrivateKeyPKCS8 nssPrivKeyInfo; PRErrorCode perr; memset(&nssPrivKeyInfo, 0, sizeof(nssPrivKeyInfo)); perr = coder.decode(p, length, kSecAsn1DSAPrivateKeyPKCS8Template, &nssPrivKeyInfo); if(perr) { logAsnErr("decode(DSA NSS_DSAPrivateKeyPKCS8)", perr); return CSSMERR_CSP_INVALID_KEY; } CSSM_RETURN crtn = nssAlgIdToDsaX509(nssPrivKeyInfo.dsaAlg, openKey); if(crtn) { return crtn; } /* * Post-decode, nssPrivKeyInfo.privateKey is the DER-encoding of a * an ASN integer. */ try { PRErrorCode perr; CSSM_DATA privKeyInt = {0, NULL}; perr = coder.decodeItem(nssPrivKeyInfo.privateKey, kSecAsn1UnsignedIntegerTemplate, &privKeyInt); if(perr) { logAsnErr("decode(DSA nssPrivKeyInfo.privateKey)", perr); return CSSMERR_CSP_INVALID_KEY; } openKey->priv_key = cssmDataToBn(privKeyInt); if(openKey->priv_key == NULL) { return CSSMERR_CSP_INVALID_KEY; } return 0; } catch(...) { return CSSMERR_CSP_INVALID_KEY; } } static CSSM_RETURN DSAPrivateKeyEncodePKCS8( SecNssCoder &coder, DSA *openKey, CssmOwnedData &encodedKey) { try { /* First convert into a NSS_DSAPrivateKeyPKCS8 */ NSS_DSAPrivateKeyPKCS8 nssPrivKey; NSS_DSAAlgParams algParams; memset(&nssPrivKey, 0, sizeof(nssPrivKey)); memset(&algParams, 0, sizeof(algParams)); nssPrivKey.dsaAlg.params = &algParams; intToCssmData(openKey->version, nssPrivKey.version, coder); dsaToNssAlgIdX509(openKey, nssPrivKey.dsaAlg, coder); /* pre-encode, nssPrivKey.privateKey is the DER-encoding of * an ASN integer... */ CSSM_DATA privKeyInt; bnToCssmData(openKey->priv_key, privKeyInt, coder); /* DER encode the privateKey portion into arena pool memory * into NSS_DSAPrivateKeyPKCS8.privateKey */ coder.encodeItem(&privKeyInt, kSecAsn1UnsignedIntegerTemplate, nssPrivKey.privateKey); /* DER encode the whole thing */ PRErrorCode perr; perr = SecNssEncodeItemOdata(&nssPrivKey, kSecAsn1DSAPrivateKeyPKCS8Template, encodedKey); return 0; } catch(...) { /* ? */ return CSSMERR_CSP_MEMORY_ERROR; } } /* * DSA public key, X509/openssl format. */ static CSSM_RETURN DSAPublicKeyDecodeX509( SecNssCoder &coder, DSA *openKey, void *p, size_t length) { NSS_DSAPublicKeyX509 nssPubKey; PRErrorCode perr; CSSM_RETURN crtn; memset(&nssPubKey, 0, sizeof(nssPubKey)); perr = coder.decode(p, length, kSecAsn1DSAPublicKeyX509Template, &nssPubKey); if(perr) { logAsnErr("decode(DSAPublicKeyX509)", perr); return CSSMERR_CSP_INVALID_KEY; } /* X509 style DSA-specific alg params */ NSS_DSAAlgorithmIdX509 &algId = nssPubKey.dsaAlg; crtn = nssAlgIdToDsaX509(algId, openKey); if(crtn) { return crtn; } /* inside of nssPubKey.publicKey is the DER-encoding of a * ASN Integer; decoded length was in bits */ nssPubKey.publicKey.Length = (nssPubKey.publicKey.Length + 7) / 8; CSSM_DATA pubKeyBytes = {0, NULL}; perr = coder.decodeItem(nssPubKey.publicKey, kSecAsn1UnsignedIntegerTemplate, &pubKeyBytes); if(perr) { logAsnErr("decode(NSS_DSAPublicKeyX509.publicKey)", perr); return CSSMERR_CSP_INVALID_KEY; } openKey->pub_key = cssmDataToBn(pubKeyBytes); if(openKey->pub_key == NULL) { return CSSMERR_CSP_INVALID_KEY; } return 0; } static CSSM_RETURN DSAPublicKeyEncodeX509( SecNssCoder &coder, DSA *openKey, CssmOwnedData &encodedKey) { try { /* convert to NSS_DSAPublicKeyX509 */ NSS_DSAPublicKeyX509 nssPubKey; NSS_DSAAlgParams algParams; memset(&nssPubKey, 0, sizeof(nssPubKey)); memset(&algParams, 0, sizeof(algParams)); nssPubKey.dsaAlg.params = &algParams; dsaToNssAlgIdX509(openKey, nssPubKey.dsaAlg, coder); /* * publicKey is the DER-encoding of a ASN INTEGER wrapped in * an AsnBits */ CSSM_DATA pubKeyRaw; PRErrorCode perr; bnToCssmData(openKey->pub_key, pubKeyRaw, coder); perr = coder.encodeItem(&pubKeyRaw, kSecAsn1UnsignedIntegerTemplate, nssPubKey.publicKey); if(perr) { logAsnErr("encodeItem(DSAPublicKeyX509.publicKey)", perr); return CSSMERR_CSP_MEMORY_ERROR; } nssPubKey.publicKey.Length *= 8; /* DER encode */ SecNssEncodeItemOdata(&nssPubKey, kSecAsn1DSAPublicKeyX509Template, encodedKey); return CSSM_OK; } catch(...) { /* ? */ return CSSMERR_CSP_MEMORY_ERROR; } } /* * Encode public key portion only for calculating key digest. * Note this works just fine on a partial DSA public key, i.e., * A DSA public key's digest-capable blob is the same whether or * not the DSA key has its DSA parameters p, q, and g. */ static CSSM_RETURN DSAPublicKeyEncodeHashable( SecNssCoder &coder, DSA *openKey, CssmOwnedData &encodedKey) { try { /* * publicKey is the DER-encoding of an ASN integer */ CSSM_DATA pubKey; bnToCssmData(openKey->pub_key, pubKey, coder); PRErrorCode perr; perr = SecNssEncodeItemOdata(&pubKey, kSecAsn1UnsignedIntegerTemplate, encodedKey); if(perr) { logAsnErr("encode(DSAPubHashable)", perr); return CSSMERR_CSP_MEMORY_ERROR; } return CSSM_OK; } catch(...) { /* ? */ return CSSMERR_CSP_MEMORY_ERROR; } } /* * DSA private key, custom openssl format. */ static CSSM_RETURN DSAPrivateKeyDecodeOpenssl( SecNssCoder &coder, DSA *openKey, void *p, size_t length) { NSS_DSAPrivateKeyOpenssl nssPrivKey; PRErrorCode perr; memset(&nssPrivKey, 0, sizeof(nssPrivKey)); perr = coder.decode(p, length, kSecAsn1DSAPrivateKeyOpensslTemplate, &nssPrivKey); if(perr) { logAsnErr("decode(DSAPrivateKeyOpenssl)", perr); return CSSMERR_CSP_INVALID_KEY; } /* convert nssPrivKey fields to RSA key fields */ try { openKey->version = cssmDataToInt(nssPrivKey.version); openKey->p = cssmDataToBn(nssPrivKey.p); openKey->q = cssmDataToBn(nssPrivKey.q); openKey->g = cssmDataToBn(nssPrivKey.g); openKey->pub_key = cssmDataToBn(nssPrivKey.pub); openKey->priv_key = cssmDataToBn(nssPrivKey.priv); } catch(...) { return CSSMERR_CSP_MEMORY_ERROR; } return 0; } static CSSM_RETURN DSAPrivateKeyEncodeOpenssl( SecNssCoder &coder, DSA *openKey, CssmOwnedData &encodedKey) { NSS_DSAPrivateKeyOpenssl nssPrivKey; PRErrorCode perr; /* convert to NSS_DSAPrivateKeyOpenssl */ try { intToCssmData(openKey->version, nssPrivKey.version, coder); bnToCssmData(openKey->p, nssPrivKey.p, coder); bnToCssmData(openKey->q, nssPrivKey.q, coder); bnToCssmData(openKey->g, nssPrivKey.g, coder); bnToCssmData(openKey->pub_key, nssPrivKey.pub, coder); bnToCssmData(openKey->priv_key, nssPrivKey.priv, coder); } catch(...) { /* ? */ return CSSMERR_CSP_MEMORY_ERROR; } /* DER encode */ perr = SecNssEncodeItemOdata(&nssPrivKey, kSecAsn1DSAPrivateKeyOpensslTemplate, encodedKey); if(perr) { logAsnErr("encode(DSAPrivateKeyOpenssl)", perr); return CSSMERR_CSP_MEMORY_ERROR; } return CSSM_OK; } CSSM_RETURN DSAPublicKeyDecode( DSA *openKey, CSSM_KEYBLOB_FORMAT format, void *p, size_t length) { SecNssCoder coder; switch(format) { case CSSM_KEYBLOB_RAW_FORMAT_FIPS186: return DSAPublicKeyDecodeFIPS186(coder, openKey, p, length); case CSSM_KEYBLOB_RAW_FORMAT_X509: return DSAPublicKeyDecodeX509(coder, openKey, p, length); case CSSM_KEYBLOB_RAW_FORMAT_OPENSSH2: return DSAPublicKeyDecodeOpenSSH2(openKey, p, length); default: assert(0); return CSSMERR_CSP_INTERNAL_ERROR; } } CSSM_RETURN DSAPublicKeyEncode( DSA *openKey, CSSM_KEYBLOB_FORMAT format, const CssmData &descData, CssmOwnedData &encodedKey) { SecNssCoder coder; switch(format) { case CSSM_KEYBLOB_RAW_FORMAT_FIPS186: return DSAPublicKeyEncodeFIPS186(coder, openKey, encodedKey); case CSSM_KEYBLOB_RAW_FORMAT_X509: return DSAPublicKeyEncodeX509(coder, openKey, encodedKey); case CSSM_KEYBLOB_RAW_FORMAT_DIGEST: return DSAPublicKeyEncodeHashable(coder, openKey, encodedKey); case CSSM_KEYBLOB_RAW_FORMAT_OPENSSH2: return DSAPublicKeyEncodeOpenSSH2(openKey, descData, encodedKey); default: assert(0); return CSSMERR_CSP_INTERNAL_ERROR; } } CSSM_RETURN DSAPrivateKeyDecode( DSA *openKey, CSSM_KEYBLOB_FORMAT format, void *p, size_t length) { SecNssCoder coder; switch(format) { case CSSM_KEYBLOB_RAW_FORMAT_FIPS186: return DSAPrivateKeyDecodeFIPS186(coder, openKey, p, (unsigned)length); case CSSM_KEYBLOB_RAW_FORMAT_OPENSSL: return DSAPrivateKeyDecodeOpenssl(coder, openKey, p, length); case CSSM_KEYBLOB_RAW_FORMAT_PKCS8: return DSAPrivateKeyDecodePKCS8(coder, openKey, p, (unsigned)length); default: assert(0); return CSSMERR_CSP_INTERNAL_ERROR; } } CSSM_RETURN DSAPrivateKeyEncode( DSA *openKey, CSSM_KEYBLOB_FORMAT format, const CssmData &descData, CssmOwnedData &encodedKey) { SecNssCoder coder; switch(format) { case CSSM_KEYBLOB_RAW_FORMAT_FIPS186: return DSAPrivateKeyEncodeFIPS186(coder, openKey, encodedKey); case CSSM_KEYBLOB_RAW_FORMAT_OPENSSL: return DSAPrivateKeyEncodeOpenssl(coder, openKey, encodedKey); case CSSM_KEYBLOB_RAW_FORMAT_PKCS8: return DSAPrivateKeyEncodePKCS8(coder, openKey, encodedKey); default: assert(0); return CSSMERR_CSP_INTERNAL_ERROR; } } #pragma mark - #pragma mark *** DSA Signature encode/decode *** CSSM_RETURN DSASigEncode( DSA_SIG *openSig, CssmOwnedData &encodedSig) { /* temp allocs from this pool */ SecNssCoder coder; /* convert to NSS_DSASignature */ NSS_DSASignature nssSig; try { bnToCssmData(openSig->r, nssSig.r, coder); bnToCssmData(openSig->s, nssSig.s, coder); } catch(...) { /* ? */ return CSSMERR_CSP_MEMORY_ERROR; } PRErrorCode prtn = SecNssEncodeItemOdata(&nssSig, kSecAsn1DSASignatureTemplate, encodedSig); if(prtn) { return CSSMERR_CSP_MEMORY_ERROR; } return CSSM_OK; } CSSM_RETURN DSASigDecode( DSA_SIG *openSig, const void *p, unsigned length) { NSS_DSASignature nssSig; SecNssCoder coder; memset(&nssSig, 0, sizeof(nssSig)); PRErrorCode perr = coder.decode(p, length, kSecAsn1DSASignatureTemplate, &nssSig); if(perr) { logAsnErr("decode(DSASigDecode)", perr); return CSSMERR_CSP_INVALID_SIGNATURE; } try { openSig->r = cssmDataToBn(nssSig.r); openSig->s = cssmDataToBn(nssSig.s); } catch(...) { return CSSMERR_CSP_MEMORY_ERROR; } return 0; } #pragma mark - #pragma mark *** DSA Algorithm Parameters encode/decode *** CSSM_RETURN DSAEncodeAlgParams( NSS_DSAAlgParams &algParams, CssmOwnedData &encodedParams) { PRErrorCode prtn = SecNssEncodeItemOdata(&algParams, kSecAsn1DSAAlgParamsTemplate, encodedParams); if(prtn) { return CSSMERR_CSP_MEMORY_ERROR; } return CSSM_OK; } CSSM_RETURN DSADecodeAlgParams( NSS_DSAAlgParams &algParams, const void *p, unsigned len, SecNssCoder &coder) { memset(&algParams, 0, sizeof(algParams)); PRErrorCode perr = coder.decode(p, len, kSecAsn1DSAAlgParamsTemplate, &algParams); if(perr) { logAsnErr("decode(DSAAlgParams)", perr); return CSSMERR_CSP_INVALID_ATTR_ALG_PARAMS; } return CSSM_OK; } #pragma mark - #pragma mark *** Diffie-Hellman key encode/decode *** static CSSM_RETURN DHPrivateKeyDecodePKCS3( SecNssCoder &coder, DH *openKey, unsigned char *p, unsigned length) { NSS_DHPrivateKey nssPrivKey; PRErrorCode perr; memset(&nssPrivKey, 0, sizeof(nssPrivKey)); perr = coder.decode(p, length, kSecAsn1DHPrivateKeyTemplate, &nssPrivKey); if(perr) { logAsnErr("decode(DHPrivateKey)", perr); return CSSMERR_CSP_INVALID_KEY; } /* verify alg identifier */ const CSSM_OID *oid = &nssPrivKey.dhOid; if(!cspCompareCssmData(oid, &CSSMOID_DH)) { sslAsn1Debug("DHPrivateKeyDecode: bad OID"); return CSSMERR_CSP_ALGID_MISMATCH; } NSS_DHParameter ¶ms = nssPrivKey.params; try { openKey->priv_key = cssmDataToBn(nssPrivKey.secretPart); openKey->p = cssmDataToBn(params.prime); openKey->g = cssmDataToBn(params.base); /* TBD - ignore privateValueLength for now */ } catch(...) { /* FIXME - bad sig? memory? */ return CSSMERR_CSP_MEMORY_ERROR; } return 0; } static CSSM_RETURN DHPrivateKeyEncodePKCS3( SecNssCoder &coder, DH *openKey, CssmOwnedData &encodedKey) { /* convert into a NSS_DHPrivateKey */ NSS_DHPrivateKey nssPrivKey; NSS_DHParameter ¶ms = nssPrivKey.params; memset(&nssPrivKey, 0, sizeof(nssPrivKey)); nssPrivKey.dhOid = CSSMOID_DH; try { bnToCssmData(openKey->priv_key, nssPrivKey.secretPart, coder); bnToCssmData(openKey->p, params.prime, coder); bnToCssmData(openKey->g, params.base, coder); if(openKey->length) { /* actually currently not supported in openssl... */ intToCssmData(openKey->length, params.privateValueLength, coder); } } catch(...) { return CSSMERR_CSP_MEMORY_ERROR; } /* DER encode */ PRErrorCode perr; perr = SecNssEncodeItemOdata(&nssPrivKey, kSecAsn1DHPrivateKeyTemplate, encodedKey); if(perr) { logAsnErr("encode(DHPrivateKey)", perr); return CSSMERR_CSP_MEMORY_ERROR; } return CSSM_OK; } /* * NSS_DHAlgorithmIdentifierX942 <--> DH * NOTE this is incomplete. It's functional on decode, but we throw * away everything except p and g. On encode, we put zeroes in * all the fields we don't deal with. Thus the encode side will NOT be * interoperable with other implementations. */ static void dhToNssAlgIdX942( const DH *openKey, NSS_DHAlgorithmIdentifierX942 &algId, SecNssCoder &coder) { /* * When trying to encode a public key in X509 form, we may in * fact have nothing here - public keys created and exported in * PKCS3 have the pub_key value, and that's it. */ memset(&algId, 0, sizeof(algId)); algId.oid = CSSMOID_ANSI_DH_PUB_NUMBER; // not mallocd NSS_DHDomainParamsX942 ¶ms = algId.params; uint8 zero = 0; CSSM_DATA czero = {1, &zero}; if(openKey->p != NULL) { bnToCssmData(openKey->p, params.p, coder); } else { coder.allocCopyItem(czero, params.p); } if(openKey->g != NULL) { bnToCssmData(openKey->g, params.g, coder); } else { coder.allocCopyItem(czero, params.g); } /* and we never have a vali0d q */ coder.allocCopyItem(czero, params.q); } static CSSM_RETURN nssAlgIdToDhX942( NSS_DHAlgorithmIdentifierX942 &algId, DH *openKey) { if(!cspCompareCssmData(&algId.oid, &CSSMOID_ANSI_DH_PUB_NUMBER)) { sslAsn1Debug("nssAlgIdToDhX942: bad OID"); return CSSMERR_CSP_INVALID_KEY; } openKey->p = cssmDataToBn(algId.params.p); openKey->g = cssmDataToBn(algId.params.g); return CSSM_OK; } static CSSM_RETURN DHPrivateKeyDecodePKCS8( SecNssCoder &coder, DH *openKey, unsigned char *p, unsigned length) { NSS_DHPrivateKeyPKCS8 nssPrivKey; PRErrorCode perr; memset(&nssPrivKey, 0, sizeof(nssPrivKey)); perr = coder.decode(p, length, kSecAsn1DHPrivateKeyPKCS8Template, &nssPrivKey); if(perr) { logAsnErr("decode(DHPrivateKeyPKCS8)", perr); return CSSMERR_CSP_INVALID_KEY; } try { CSSM_RETURN crtn = nssAlgIdToDhX942(nssPrivKey.algorithm, openKey); if(crtn) { return crtn; } /* post-decode private key is a DER encoded integer */ CSSM_DATA privKeyInt = {0, NULL}; if(coder.decodeItem(nssPrivKey.privateKey, kSecAsn1UnsignedIntegerTemplate, &privKeyInt)) { logAsnErr("decode(DHPrivateKeyPKCS8 privKey int)", perr); return CSSMERR_CSP_INVALID_KEY; } openKey->priv_key = cssmDataToBn(privKeyInt); } catch(...) { /* FIXME - bad sig? memory? */ return CSSMERR_CSP_MEMORY_ERROR; } return 0; } static CSSM_RETURN DHPrivateKeyEncodePKCS8( SecNssCoder &coder, DH *openKey, CssmOwnedData &encodedKey) { /* convert into a NSS_DHPrivateKeyPKCS8 */ NSS_DHPrivateKeyPKCS8 nssPrivKey; memset(&nssPrivKey, 0, sizeof(nssPrivKey)); uint8 vers = 0; nssPrivKey.version.Length = 1; nssPrivKey.version.Data = &vers; NSS_DHAlgorithmIdentifierX942 &alg = nssPrivKey.algorithm; try { dhToNssAlgIdX942(openKey, alg, coder); /* pre-encode, nssPrivKey.privateKey is the DER-encoding of * an ASN integer... */ CSSM_DATA privKeyInt; bnToCssmData(openKey->priv_key, privKeyInt, coder); /* DER encode the privateKey portion into arena pool memory * into nssPrivKey.privateKey */ coder.encodeItem(&privKeyInt, kSecAsn1UnsignedIntegerTemplate, nssPrivKey.privateKey); } catch(...) { return CSSMERR_CSP_MEMORY_ERROR; } /* DER encode */ PRErrorCode perr; perr = SecNssEncodeItemOdata(&nssPrivKey, kSecAsn1DHPrivateKeyPKCS8Template, encodedKey); if(perr) { logAsnErr("encode(DHPrivateKey)", perr); return CSSMERR_CSP_MEMORY_ERROR; } return CSSM_OK; } /* * In the PKCS3 form, the public blob is simply the literal * public key value, not DER encoded. */ static CSSM_RETURN DHPublicKeyDecodePKCS3( DH *openKey, SecNssCoder &coder, unsigned char *p, unsigned length) { try { CSSM_DATA pubKey = {(uint32)length, (uint8 *)p}; openKey->pub_key = cssmDataToBn(pubKey); return CSSM_OK; } catch(...) { return CSSMERR_CSP_MEMORY_ERROR; } } static CSSM_RETURN DHPublicKeyEncodePKCS3( DH *openKey, SecNssCoder &coder, CssmOwnedData &encodedKey) { try { CSSM_DATA pubKey; bnToCssmData(openKey->pub_key, pubKey, coder); encodedKey.copy(CssmData::overlay(pubKey)); return CSSM_OK; } catch(...) { return CSSMERR_CSP_MEMORY_ERROR; } } static CSSM_RETURN DHPublicKeyDecodeX509( DH *openKey, SecNssCoder &coder, unsigned char *p, unsigned length) { NSS_DHPublicKeyX509 nssPubKey; PRErrorCode perr; memset(&nssPubKey, 0, sizeof(nssPubKey)); perr = coder.decode(p, length, kSecAsn1DHPublicKeyX509Template, &nssPubKey); if(perr) { logAsnErr("decode(DHPublicKeyX509)", perr); return CSSMERR_CSP_INVALID_KEY; } try { CSSM_RETURN crtn = nssAlgIdToDhX942(nssPubKey.algorithm, openKey); if(crtn) { return crtn; } /* * Post-decode public key length in bits * Contents are pub_key as DER-encoded INTEGER */ CSSM_DATA &pubKey = nssPubKey.publicKey; pubKey.Length = (pubKey.Length + 7) / 8; CSSM_DATA pubKeyInt = {0, NULL}; if(coder.decodeItem(pubKey, kSecAsn1UnsignedIntegerTemplate, &pubKeyInt)) { logAsnErr("decode(DHPublicKeyX509 pub key int)", perr); return CSSMERR_CSP_INVALID_KEY; } openKey->pub_key = cssmDataToBn(pubKeyInt); } catch(...) { /* FIXME - bad sig? memory? */ return CSSMERR_CSP_MEMORY_ERROR; } return 0; } static CSSM_RETURN DHPublicKeyEncodeX509( DH *openKey, SecNssCoder &coder, CssmOwnedData &encodedKey) { /* convert into a NSS_DHPublicKeyX509 */ NSS_DHPublicKeyX509 nssPubKey; memset(&nssPubKey, 0, sizeof(nssPubKey)); NSS_DHAlgorithmIdentifierX942 &alg = nssPubKey.algorithm; try { dhToNssAlgIdX942(openKey, alg, coder); /* encode pub_key as integer */ CSSM_DATA pubKeyInt = {0, NULL}; bnToCssmData(openKey->pub_key, pubKeyInt, coder); coder.encodeItem(&pubKeyInt, kSecAsn1UnsignedIntegerTemplate, nssPubKey.publicKey); /* specify length in bits */ nssPubKey.publicKey.Length *= 8; } catch(...) { return CSSMERR_CSP_MEMORY_ERROR; } /* DER encode */ PRErrorCode perr; perr = SecNssEncodeItemOdata(&nssPubKey, kSecAsn1DHPublicKeyX509Template, encodedKey); if(perr) { logAsnErr("encode(DHPublicKeyX509)", perr); return CSSMERR_CSP_MEMORY_ERROR; } return CSSM_OK; } CSSM_RETURN DHPrivateKeyDecode( DH *openKey, CSSM_KEYBLOB_FORMAT format, unsigned char *p, unsigned length) { SecNssCoder coder; switch(format) { case CSSM_KEYBLOB_RAW_FORMAT_PKCS3: return DHPrivateKeyDecodePKCS3(coder, openKey, p, length); case CSSM_KEYBLOB_RAW_FORMAT_PKCS8: return DHPrivateKeyDecodePKCS8(coder, openKey, p, length); default: assert(0); return CSSMERR_CSP_INTERNAL_ERROR; } } CSSM_RETURN DHPrivateKeyEncode( DH *openKey, CSSM_KEYBLOB_FORMAT format, CssmOwnedData &encodedKey) { SecNssCoder coder; switch(format) { case CSSM_KEYBLOB_RAW_FORMAT_PKCS3: return DHPrivateKeyEncodePKCS3(coder, openKey, encodedKey); case CSSM_KEYBLOB_RAW_FORMAT_PKCS8: return DHPrivateKeyEncodePKCS8(coder, openKey, encodedKey); default: assert(0); return CSSMERR_CSP_INTERNAL_ERROR; } } CSSM_RETURN DHPublicKeyDecode( DH *openKey, CSSM_KEYBLOB_FORMAT format, unsigned char *p, unsigned length) { SecNssCoder coder; switch(format) { case CSSM_KEYBLOB_RAW_FORMAT_PKCS3: return DHPublicKeyDecodePKCS3(openKey, coder, p, length); case CSSM_KEYBLOB_RAW_FORMAT_X509: return DHPublicKeyDecodeX509(openKey, coder, p, length); default: assert(0); return CSSMERR_CSP_INTERNAL_ERROR; } } CSSM_RETURN DHPublicKeyEncode( DH *openKey, CSSM_KEYBLOB_FORMAT format, CssmOwnedData &encodedKey) { SecNssCoder coder; switch(format) { case CSSM_KEYBLOB_RAW_FORMAT_PKCS3: return DHPublicKeyEncodePKCS3(openKey, coder, encodedKey); case CSSM_KEYBLOB_RAW_FORMAT_X509: return DHPublicKeyEncodeX509(openKey, coder, encodedKey); default: assert(0); return CSSMERR_CSP_INTERNAL_ERROR; } } /* * Encode/decode a NSS_DHParameterBlock. */ CSSM_RETURN DHParamBlockDecode( const CSSM_DATA &encParam, NSS_DHParameterBlock ¶mBlock, SecNssCoder &coder) { PRErrorCode perr; memset(¶mBlock, 0, sizeof(paramBlock)); perr = coder.decodeItem(encParam, kSecAsn1DHParameterBlockTemplate, ¶mBlock); if(perr == 0) { return CSSM_OK; } /* * CDSA Extension: the CDSA Algorithm Guide says that the D-H * parameter block is supposed to be wrapped with its accompanying * OID. However Openssl does not do this; it just exports * an encoded DHParameter rather than a DHParameterBlock. * For compatibility we'll try decoding the parameters as one * of these. */ memset(¶mBlock, 0, sizeof(paramBlock)); perr = coder.decodeItem(encParam, kSecAsn1DHParameterTemplate, ¶mBlock.params); if(perr == 0) { return CSSM_OK; } return CSSMERR_CSP_INVALID_ATTR_ALG_PARAMS; } #pragma mark - #pragma mark *** Message Digest *** /* * Given a message digest and associated algorithm, cook up a PKCS1-style * DigestInfo and return its DER encoding. This is a necessary step for * RSA signature (both generating and verifying) - the output of this * routine is what gets encrypted during signing, and what is expected when * verifying (i.e., decrypting the signature). * * A good guess for the length of the output digestInfo is the size of the * key being used to sign/verify. The digest can never be larger than that. */ CSSM_RETURN generateDigestInfo( const void *msgDigest, size_t digestLen, CSSM_ALGORITHMS digestAlg, // CSSM_ALGID_SHA1, etc. CssmOwnedData &encodedInfo, size_t maxEncodedSize) { if(digestAlg == CSSM_ALGID_NONE) { /* special case, no encode, just copy */ encodedInfo.copy(msgDigest, digestLen); return 0; } NSS_DigestInfo digestInfo; CSSM_X509_ALGORITHM_IDENTIFIER &algId = digestInfo.digestAlgorithm; memset(&digestInfo, 0, sizeof(digestInfo)); switch(digestAlg) { case CSSM_ALGID_MD5: algId.algorithm = CSSMOID_MD5; break; case CSSM_ALGID_MD2: algId.algorithm = CSSMOID_MD2; break; case CSSM_ALGID_SHA1: algId.algorithm = CSSMOID_SHA1; break; case CSSM_ALGID_SHA224: algId.algorithm = CSSMOID_SHA224; break; case CSSM_ALGID_SHA256: algId.algorithm = CSSMOID_SHA256; break; case CSSM_ALGID_SHA384: algId.algorithm = CSSMOID_SHA384; break; case CSSM_ALGID_SHA512: algId.algorithm = CSSMOID_SHA512; break; default: return CSSMERR_CSP_INVALID_ALGORITHM; } nullAlgParams(algId); digestInfo.digest.Data = (uint8 *)msgDigest; digestInfo.digest.Length = digestLen; /* DER encode */ PRErrorCode perr; perr = SecNssEncodeItemOdata(&digestInfo, kSecAsn1DigestInfoTemplate, encodedInfo); if(perr) { logAsnErr("encode(digestInfo)", perr); return CSSMERR_CSP_MEMORY_ERROR; } return CSSM_OK; }