From 030f9ff85ec40167b5d885c980a44c090e5729d6 Mon Sep 17 00:00:00 2001 From: Rich Megginson Date: Mon, 12 Jul 2010 16:31:01 -0600 Subject: Add support for PKCS#8 encoded private keys The code supports PKCS#1 encoded RSA private keys that begin with the BEGIN RSA PRIVATE KEY header in PEM files. This patch adds support for RSA private keys encoded in PEM files that begin with the header BEGIN PRIVATE KEY which are in PKCS#8 format. --- prsa.c | 150 +++++++++++++++++++++++++++++++++++++++++++++++------------------ util.c | 3 +- 2 files changed, 110 insertions(+), 43 deletions(-) diff --git a/prsa.c b/prsa.c index 5b2f379..8d4fb92 100644 --- a/prsa.c +++ b/prsa.c @@ -63,6 +63,35 @@ const SEC_ASN1Template pem_RSAPrivateKeyTemplate[] = { {0} }; +static const SEC_ASN1Template pem_AttributeTemplate[] = { + { SEC_ASN1_SEQUENCE, + 0, NULL, sizeof(NSSLOWKEYAttribute) }, + { SEC_ASN1_OBJECT_ID, offsetof(NSSLOWKEYAttribute, attrType) }, + { SEC_ASN1_SET_OF | SEC_ASN1_XTRN, offsetof(NSSLOWKEYAttribute, attrValue), + SEC_ASN1_SUB(SEC_AnyTemplate) }, + { 0 } +}; + +static const SEC_ASN1Template pem_SetOfAttributeTemplate[] = { + { SEC_ASN1_SET_OF, 0, pem_AttributeTemplate }, +}; + +const SEC_ASN1Template pem_PrivateKeyInfoTemplate[] = { + { SEC_ASN1_SEQUENCE, + 0, NULL, sizeof(NSSLOWKEYPrivateKeyInfo) }, + { SEC_ASN1_INTEGER, + offsetof(NSSLOWKEYPrivateKeyInfo,version) }, + { SEC_ASN1_INLINE | SEC_ASN1_XTRN, + offsetof(NSSLOWKEYPrivateKeyInfo,algorithm), + SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, + { SEC_ASN1_OCTET_STRING, + offsetof(NSSLOWKEYPrivateKeyInfo,privateKey) }, + { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0, + offsetof(NSSLOWKEYPrivateKeyInfo, attributes), + pem_SetOfAttributeTemplate }, + { 0 } +}; + /* Declarations */ SECStatus pem_RSA_Sign(pemLOWKEYPrivateKey * key, unsigned char *output, unsigned int *outputLen, unsigned int maxOutputLen, @@ -116,6 +145,79 @@ pem_DestroyPrivateKey(pemLOWKEYPrivateKey * privk) nss_ZFreeIf(privk); } +/* decode and parse the rawkey into the lpk structure */ +static pemLOWKEYPrivateKey * +pem_getPrivateKey(PLArenaPool *arena, SECItem *rawkey, CK_RV * pError, NSSItem *modulus) +{ + pemLOWKEYPrivateKey *lpk = NULL; + SECStatus rv = SECFailure; + NSSLOWKEYPrivateKeyInfo *pki = NULL; + SECItem *keysrc = NULL; + + /* make sure SECOID is initialized - not sure why we have to do this outside of nss_Init */ + if (SECSuccess != (rv = SECOID_Init())) { + *pError = CKR_GENERAL_ERROR; + return NULL; /* wha???? */ + } + + pki = (NSSLOWKEYPrivateKeyInfo*)PORT_ArenaZAlloc(arena, + sizeof(NSSLOWKEYPrivateKeyInfo)); + if(!pki) { + *pError = CKR_HOST_MEMORY; + goto done; + } + + /* let's first see if this is a "raw" RSA private key or an RSA private key in PKCS#8 format */ + rv = SEC_ASN1DecodeItem(arena, pki, pem_PrivateKeyInfoTemplate, rawkey); + if (rv != SECSuccess) { + /* not PKCS#8 - assume it's a "raw" RSA private key */ + keysrc = rawkey; + } else if (SECOID_GetAlgorithmTag(&pki->algorithm) == SEC_OID_PKCS1_RSA_ENCRYPTION) { + keysrc = &pki->privateKey; + } else { /* unsupported */ + *pError = CKR_FUNCTION_NOT_SUPPORTED; + goto done; + } + + lpk = (pemLOWKEYPrivateKey *) nss_ZAlloc(NULL, + sizeof(pemLOWKEYPrivateKey)); + if (lpk == NULL) { + *pError = CKR_HOST_MEMORY; + goto done; + } + + lpk->arena = arena; + lpk->keyType = pemLOWKEYRSAKey; + prepare_low_rsa_priv_key_for_asn1(lpk); + + /* I don't know what this is supposed to accomplish. We free the old + modulus data and set it again, making a copy of the new data. + But we just allocated a new empty key structure above with + nss_ZAlloc. So lpk->u.rsa.modulus.data is NULL and + lpk->u.rsa.modulus.len. If the intention is to free the old + modulus data, why not just set it to NULL after freeing? Why + go through this unnecessary and confusing copying code? + */ + if (modulus) { + nss_ZFreeIf(modulus->data); + modulus->data = (void *) nss_ZAlloc(NULL, lpk->u.rsa.modulus.len); + modulus->size = lpk->u.rsa.modulus.len; + nsslibc_memcpy(modulus->data, lpk->u.rsa.modulus.data, + lpk->u.rsa.modulus.len); + } + + /* decode the private key and any algorithm parameters */ + rv = SEC_QuickDERDecodeItem(arena, lpk, pem_RSAPrivateKeyTemplate, + keysrc); + + if (rv != SECSuccess) { + goto done; + } + +done: + return lpk; +} + void pem_PopulateModulusExponent(pemInternalObject * io) { @@ -123,7 +225,7 @@ pem_PopulateModulusExponent(pemInternalObject * io) const NSSItem *keyType = pem_FetchAttribute(io, CKA_KEY_TYPE); pemLOWKEYPrivateKey *lpk = NULL; PLArenaPool *arena; - SECStatus rv; + CK_RV pError = 0; /* make sure we have the right objects */ if (((const NSSItem *) NULL == classItem) || @@ -140,26 +242,12 @@ pem_PopulateModulusExponent(pemInternalObject * io) return; } - lpk = (pemLOWKEYPrivateKey *) nss_ZAlloc(NULL, - sizeof(pemLOWKEYPrivateKey)); + lpk = pem_getPrivateKey(arena, io->u.key.key.privateKey, &pError, NULL); if (lpk == NULL) { PORT_FreeArena(arena, PR_FALSE); return; } - lpk->arena = arena; - lpk->keyType = pemLOWKEYRSAKey; - prepare_low_rsa_priv_key_for_asn1(lpk); - - /* decode the private key and any algorithm parameters */ - rv = SEC_QuickDERDecodeItem(arena, lpk, pem_RSAPrivateKeyTemplate, - io->u.key.key.privateKey); - - if (rv != SECSuccess) { - PORT_FreeArena(arena, PR_FALSE); - return; - } - nss_ZFreeIf(io->u.key.key.modulus.data); io->u.key.key.modulus.data = (void *) nss_ZAlloc(NULL, lpk->u.rsa.modulus.len); @@ -252,13 +340,6 @@ pem_mdCryptoOperationRSAPriv_Create pemInternalCryptoOperationRSAPriv *iOperation; pemLOWKEYPrivateKey *lpk = NULL; PLArenaPool *arena; - SECStatus rv; - - arena = PORT_NewArena(2048); - if (!arena) { - *pError = CKR_HOST_MEMORY; - return (NSSCKMDCryptoOperation *) NULL; - } /* make sure we have the right objects */ if (((const NSSItem *) NULL == classItem) || @@ -271,30 +352,15 @@ pem_mdCryptoOperationRSAPriv_Create return (NSSCKMDCryptoOperation *) NULL; } - lpk = (pemLOWKEYPrivateKey *) nss_ZAlloc(NULL, - sizeof (pemLOWKEYPrivateKey)); - if (lpk == NULL) { + arena = PORT_NewArena(2048); + if (!arena) { *pError = CKR_HOST_MEMORY; return (NSSCKMDCryptoOperation *) NULL; } - lpk->arena = arena; - lpk->keyType = pemLOWKEYRSAKey; - prepare_low_rsa_priv_key_for_asn1(lpk); - nss_ZFreeIf(iKey->u.key.key.modulus.data); - iKey->u.key.key.modulus.data = - (void *) nss_ZAlloc(NULL, lpk->u.rsa.modulus.len); - iKey->u.key.key.modulus.size = lpk->u.rsa.modulus.len; - nsslibc_memcpy(iKey->u.key.key.modulus.data, lpk->u.rsa.modulus.data, - lpk->u.rsa.modulus.len); - - /* decode the private key and any algorithm parameters */ - rv = SEC_QuickDERDecodeItem(arena, lpk, pem_RSAPrivateKeyTemplate, - iKey->u.key.key.privateKey); - - if (rv != SECSuccess) { + lpk = pem_getPrivateKey(arena, iKey->u.key.key.privateKey, pError, &iKey->u.key.key.modulus); + if (lpk == NULL) { PORT_FreeArena(arena, PR_FALSE); - *pError = CKR_HOST_MEMORY; return (NSSCKMDCryptoOperation *) NULL; } diff --git a/util.c b/util.c index a6ca094..d02ee87 100644 --- a/util.c +++ b/util.c @@ -164,7 +164,8 @@ ReadDERFromFile(SECItem *** derlist, char *filename, PRBool ascii, int key = 0; while ((asc) && ((body = strstr(asc, "-----BEGIN")) != NULL)) { key = 0; - if (strncmp(body, "-----BEGIN RSA PRIVATE KEY", 25) == 0) { + if ((strncmp(body, "-----BEGIN RSA PRIVATE KEY", 25) == 0) || + (strncmp(body, "-----BEGIN PRIVATE KEY", 21) == 0)) { key = 1; c = body; body = strchr(body, '\n'); -- cgit