]>
Commit | Line | Data |
---|---|---|
137c9981 MT |
1 | From 8bd0a0427e034262ff982fed98ca5e8c623165db Mon Sep 17 00:00:00 2001 |
2 | From: Rich Megginson <rmeggins@redhat.com> | |
3 | Date: Mon, 12 Jul 2010 16:31:01 -0600 | |
4 | Subject: [PATCH] Add support for PKCS#8 encoded private keys | |
5 | ||
6 | The code supports PKCS#1 encoded RSA private keys that begin with the | |
7 | BEGIN RSA PRIVATE KEY header in PEM files. This patch adds support for | |
8 | RSA private keys encoded in PEM files that begin with the header | |
9 | BEGIN PRIVATE KEY which are in PKCS#8 format. | |
10 | --- | |
11 | prsa.c | 150 ++++++++++++++++++++++++++++++++++++++++++++++------------------ | |
12 | util.c | 3 +- | |
13 | 2 files changed, 110 insertions(+), 43 deletions(-) | |
14 | ||
15 | diff --git a/prsa.c b/prsa.c | |
16 | index 5b2f379..8d4fb92 100644 | |
17 | --- a/mozilla/security/nss/lib/ckfw/pem/prsa.c | |
18 | +++ b/mozilla/security/nss/lib/ckfw/pem/prsa.c | |
19 | @@ -63,6 +63,35 @@ const SEC_ASN1Template pem_RSAPrivateKeyTemplate[] = { | |
20 | {0} | |
21 | }; | |
22 | ||
23 | +static const SEC_ASN1Template pem_AttributeTemplate[] = { | |
24 | + { SEC_ASN1_SEQUENCE, | |
25 | + 0, NULL, sizeof(NSSLOWKEYAttribute) }, | |
26 | + { SEC_ASN1_OBJECT_ID, offsetof(NSSLOWKEYAttribute, attrType) }, | |
27 | + { SEC_ASN1_SET_OF | SEC_ASN1_XTRN, offsetof(NSSLOWKEYAttribute, attrValue), | |
28 | + SEC_ASN1_SUB(SEC_AnyTemplate) }, | |
29 | + { 0 } | |
30 | +}; | |
31 | + | |
32 | +static const SEC_ASN1Template pem_SetOfAttributeTemplate[] = { | |
33 | + { SEC_ASN1_SET_OF, 0, pem_AttributeTemplate }, | |
34 | +}; | |
35 | + | |
36 | +const SEC_ASN1Template pem_PrivateKeyInfoTemplate[] = { | |
37 | + { SEC_ASN1_SEQUENCE, | |
38 | + 0, NULL, sizeof(NSSLOWKEYPrivateKeyInfo) }, | |
39 | + { SEC_ASN1_INTEGER, | |
40 | + offsetof(NSSLOWKEYPrivateKeyInfo,version) }, | |
41 | + { SEC_ASN1_INLINE | SEC_ASN1_XTRN, | |
42 | + offsetof(NSSLOWKEYPrivateKeyInfo,algorithm), | |
43 | + SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, | |
44 | + { SEC_ASN1_OCTET_STRING, | |
45 | + offsetof(NSSLOWKEYPrivateKeyInfo,privateKey) }, | |
46 | + { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0, | |
47 | + offsetof(NSSLOWKEYPrivateKeyInfo, attributes), | |
48 | + pem_SetOfAttributeTemplate }, | |
49 | + { 0 } | |
50 | +}; | |
51 | + | |
52 | /* Declarations */ | |
53 | SECStatus pem_RSA_Sign(pemLOWKEYPrivateKey * key, unsigned char *output, | |
54 | unsigned int *outputLen, unsigned int maxOutputLen, | |
55 | @@ -116,6 +145,79 @@ pem_DestroyPrivateKey(pemLOWKEYPrivateKey * privk) | |
56 | nss_ZFreeIf(privk); | |
57 | } | |
58 | ||
59 | +/* decode and parse the rawkey into the lpk structure */ | |
60 | +static pemLOWKEYPrivateKey * | |
61 | +pem_getPrivateKey(PLArenaPool *arena, SECItem *rawkey, CK_RV * pError, NSSItem *modulus) | |
62 | +{ | |
63 | + pemLOWKEYPrivateKey *lpk = NULL; | |
64 | + SECStatus rv = SECFailure; | |
65 | + NSSLOWKEYPrivateKeyInfo *pki = NULL; | |
66 | + SECItem *keysrc = NULL; | |
67 | + | |
68 | + /* make sure SECOID is initialized - not sure why we have to do this outside of nss_Init */ | |
69 | + if (SECSuccess != (rv = SECOID_Init())) { | |
70 | + *pError = CKR_GENERAL_ERROR; | |
71 | + return NULL; /* wha???? */ | |
72 | + } | |
73 | + | |
74 | + pki = (NSSLOWKEYPrivateKeyInfo*)PORT_ArenaZAlloc(arena, | |
75 | + sizeof(NSSLOWKEYPrivateKeyInfo)); | |
76 | + if(!pki) { | |
77 | + *pError = CKR_HOST_MEMORY; | |
78 | + goto done; | |
79 | + } | |
80 | + | |
81 | + /* let's first see if this is a "raw" RSA private key or an RSA private key in PKCS#8 format */ | |
82 | + rv = SEC_ASN1DecodeItem(arena, pki, pem_PrivateKeyInfoTemplate, rawkey); | |
83 | + if (rv != SECSuccess) { | |
84 | + /* not PKCS#8 - assume it's a "raw" RSA private key */ | |
85 | + keysrc = rawkey; | |
86 | + } else if (SECOID_GetAlgorithmTag(&pki->algorithm) == SEC_OID_PKCS1_RSA_ENCRYPTION) { | |
87 | + keysrc = &pki->privateKey; | |
88 | + } else { /* unsupported */ | |
89 | + *pError = CKR_FUNCTION_NOT_SUPPORTED; | |
90 | + goto done; | |
91 | + } | |
92 | + | |
93 | + lpk = (pemLOWKEYPrivateKey *) nss_ZAlloc(NULL, | |
94 | + sizeof(pemLOWKEYPrivateKey)); | |
95 | + if (lpk == NULL) { | |
96 | + *pError = CKR_HOST_MEMORY; | |
97 | + goto done; | |
98 | + } | |
99 | + | |
100 | + lpk->arena = arena; | |
101 | + lpk->keyType = pemLOWKEYRSAKey; | |
102 | + prepare_low_rsa_priv_key_for_asn1(lpk); | |
103 | + | |
104 | + /* I don't know what this is supposed to accomplish. We free the old | |
105 | + modulus data and set it again, making a copy of the new data. | |
106 | + But we just allocated a new empty key structure above with | |
107 | + nss_ZAlloc. So lpk->u.rsa.modulus.data is NULL and | |
108 | + lpk->u.rsa.modulus.len. If the intention is to free the old | |
109 | + modulus data, why not just set it to NULL after freeing? Why | |
110 | + go through this unnecessary and confusing copying code? | |
111 | + */ | |
112 | + if (modulus) { | |
113 | + nss_ZFreeIf(modulus->data); | |
114 | + modulus->data = (void *) nss_ZAlloc(NULL, lpk->u.rsa.modulus.len); | |
115 | + modulus->size = lpk->u.rsa.modulus.len; | |
116 | + nsslibc_memcpy(modulus->data, lpk->u.rsa.modulus.data, | |
117 | + lpk->u.rsa.modulus.len); | |
118 | + } | |
119 | + | |
120 | + /* decode the private key and any algorithm parameters */ | |
121 | + rv = SEC_QuickDERDecodeItem(arena, lpk, pem_RSAPrivateKeyTemplate, | |
122 | + keysrc); | |
123 | + | |
124 | + if (rv != SECSuccess) { | |
125 | + goto done; | |
126 | + } | |
127 | + | |
128 | +done: | |
129 | + return lpk; | |
130 | +} | |
131 | + | |
132 | void | |
133 | pem_PopulateModulusExponent(pemInternalObject * io) | |
134 | { | |
135 | @@ -123,7 +225,7 @@ pem_PopulateModulusExponent(pemInternalObject * io) | |
136 | const NSSItem *keyType = pem_FetchAttribute(io, CKA_KEY_TYPE); | |
137 | pemLOWKEYPrivateKey *lpk = NULL; | |
138 | PLArenaPool *arena; | |
139 | - SECStatus rv; | |
140 | + CK_RV pError = 0; | |
141 | ||
142 | /* make sure we have the right objects */ | |
143 | if (((const NSSItem *) NULL == classItem) || | |
144 | @@ -140,26 +242,12 @@ pem_PopulateModulusExponent(pemInternalObject * io) | |
145 | return; | |
146 | } | |
147 | ||
148 | - lpk = (pemLOWKEYPrivateKey *) nss_ZAlloc(NULL, | |
149 | - sizeof(pemLOWKEYPrivateKey)); | |
150 | + lpk = pem_getPrivateKey(arena, io->u.key.key.privateKey, &pError, NULL); | |
151 | if (lpk == NULL) { | |
152 | PORT_FreeArena(arena, PR_FALSE); | |
153 | return; | |
154 | } | |
155 | ||
156 | - lpk->arena = arena; | |
157 | - lpk->keyType = pemLOWKEYRSAKey; | |
158 | - prepare_low_rsa_priv_key_for_asn1(lpk); | |
159 | - | |
160 | - /* decode the private key and any algorithm parameters */ | |
161 | - rv = SEC_QuickDERDecodeItem(arena, lpk, pem_RSAPrivateKeyTemplate, | |
162 | - io->u.key.key.privateKey); | |
163 | - | |
164 | - if (rv != SECSuccess) { | |
165 | - PORT_FreeArena(arena, PR_FALSE); | |
166 | - return; | |
167 | - } | |
168 | - | |
169 | nss_ZFreeIf(io->u.key.key.modulus.data); | |
170 | io->u.key.key.modulus.data = | |
171 | (void *) nss_ZAlloc(NULL, lpk->u.rsa.modulus.len); | |
172 | @@ -252,13 +340,6 @@ pem_mdCryptoOperationRSAPriv_Create | |
173 | pemInternalCryptoOperationRSAPriv *iOperation; | |
174 | pemLOWKEYPrivateKey *lpk = NULL; | |
175 | PLArenaPool *arena; | |
176 | - SECStatus rv; | |
177 | - | |
178 | - arena = PORT_NewArena(2048); | |
179 | - if (!arena) { | |
180 | - *pError = CKR_HOST_MEMORY; | |
181 | - return (NSSCKMDCryptoOperation *) NULL; | |
182 | - } | |
183 | ||
184 | /* make sure we have the right objects */ | |
185 | if (((const NSSItem *) NULL == classItem) || | |
186 | @@ -271,30 +352,15 @@ pem_mdCryptoOperationRSAPriv_Create | |
187 | return (NSSCKMDCryptoOperation *) NULL; | |
188 | } | |
189 | ||
190 | - lpk = (pemLOWKEYPrivateKey *) nss_ZAlloc(NULL, | |
191 | - sizeof (pemLOWKEYPrivateKey)); | |
192 | - if (lpk == NULL) { | |
193 | + arena = PORT_NewArena(2048); | |
194 | + if (!arena) { | |
195 | *pError = CKR_HOST_MEMORY; | |
196 | return (NSSCKMDCryptoOperation *) NULL; | |
197 | } | |
198 | - lpk->arena = arena; | |
199 | - lpk->keyType = pemLOWKEYRSAKey; | |
200 | - prepare_low_rsa_priv_key_for_asn1(lpk); | |
201 | ||
202 | - nss_ZFreeIf(iKey->u.key.key.modulus.data); | |
203 | - iKey->u.key.key.modulus.data = | |
204 | - (void *) nss_ZAlloc(NULL, lpk->u.rsa.modulus.len); | |
205 | - iKey->u.key.key.modulus.size = lpk->u.rsa.modulus.len; | |
206 | - nsslibc_memcpy(iKey->u.key.key.modulus.data, lpk->u.rsa.modulus.data, | |
207 | - lpk->u.rsa.modulus.len); | |
208 | - | |
209 | - /* decode the private key and any algorithm parameters */ | |
210 | - rv = SEC_QuickDERDecodeItem(arena, lpk, pem_RSAPrivateKeyTemplate, | |
211 | - iKey->u.key.key.privateKey); | |
212 | - | |
213 | - if (rv != SECSuccess) { | |
214 | + lpk = pem_getPrivateKey(arena, iKey->u.key.key.privateKey, pError, &iKey->u.key.key.modulus); | |
215 | + if (lpk == NULL) { | |
216 | PORT_FreeArena(arena, PR_FALSE); | |
217 | - *pError = CKR_HOST_MEMORY; | |
218 | return (NSSCKMDCryptoOperation *) NULL; | |
219 | } | |
220 | ||
221 | diff --git a/util.c b/util.c | |
222 | index a6ca094..d02ee87 100644 | |
223 | --- a/mozilla/security/nss/lib/ckfw/pem/util.c | |
224 | +++ b/mozilla/security/nss/lib/ckfw/pem/util.c | |
225 | @@ -164,7 +164,8 @@ ReadDERFromFile(SECItem *** derlist, char *filename, PRBool ascii, | |
226 | int key = 0; | |
227 | while ((asc) && ((body = strstr(asc, "-----BEGIN")) != NULL)) { | |
228 | key = 0; | |
229 | - if (strncmp(body, "-----BEGIN RSA PRIVATE KEY", 25) == 0) { | |
230 | + if ((strncmp(body, "-----BEGIN RSA PRIVATE KEY", 25) == 0) || | |
231 | + (strncmp(body, "-----BEGIN PRIVATE KEY", 21) == 0)) { | |
232 | key = 1; | |
233 | c = body; | |
234 | body = strchr(body, '\n'); | |
235 | -- | |
236 | 1.5.5.6 | |
237 |