1 /* -*- Mode: C; tab-width: 8 -*-*/
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 /*
7  * This file will implement the functions related to key recovery in
8  * CMMF
9  */
10 
11 #include "cmmf.h"
12 #include "cmmfi.h"
13 #include "secitem.h"
14 #include "keyhi.h"
15 
16 CMMFKeyRecRepContent *
CMMF_CreateKeyRecRepContent(void)17 CMMF_CreateKeyRecRepContent(void)
18 {
19     PLArenaPool *poolp;
20     CMMFKeyRecRepContent *keyRecContent;
21 
22     poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE);
23     if (poolp == NULL) {
24         return NULL;
25     }
26     keyRecContent = PORT_ArenaZNew(poolp, CMMFKeyRecRepContent);
27     if (keyRecContent == NULL) {
28         PORT_FreeArena(poolp, PR_FALSE);
29         return NULL;
30     }
31     keyRecContent->poolp = poolp;
32     return keyRecContent;
33 }
34 
35 SECStatus
CMMF_DestroyKeyRecRepContent(CMMFKeyRecRepContent * inKeyRecRep)36 CMMF_DestroyKeyRecRepContent(CMMFKeyRecRepContent *inKeyRecRep)
37 {
38     PORT_Assert(inKeyRecRep != NULL);
39     if (inKeyRecRep != NULL && inKeyRecRep->poolp != NULL) {
40         int i;
41 
42         if (!inKeyRecRep->isDecoded && inKeyRecRep->newSigCert != NULL) {
43             CERT_DestroyCertificate(inKeyRecRep->newSigCert);
44         }
45         if (inKeyRecRep->caCerts != NULL) {
46             for (i = 0; inKeyRecRep->caCerts[i] != NULL; i++) {
47                 CERT_DestroyCertificate(inKeyRecRep->caCerts[i]);
48             }
49         }
50         if (inKeyRecRep->keyPairHist != NULL) {
51             for (i = 0; inKeyRecRep->keyPairHist[i] != NULL; i++) {
52                 if (inKeyRecRep->keyPairHist[i]->certOrEncCert.choice ==
53                     cmmfCertificate) {
54                     CERT_DestroyCertificate(inKeyRecRep->keyPairHist[i]->certOrEncCert.cert.certificate);
55                 }
56             }
57         }
58         PORT_FreeArena(inKeyRecRep->poolp, PR_TRUE);
59     }
60     return SECSuccess;
61 }
62 
63 SECStatus
CMMF_KeyRecRepContentSetPKIStatusInfoStatus(CMMFKeyRecRepContent * inKeyRecRep,CMMFPKIStatus inPKIStatus)64 CMMF_KeyRecRepContentSetPKIStatusInfoStatus(CMMFKeyRecRepContent *inKeyRecRep,
65                                             CMMFPKIStatus inPKIStatus)
66 {
67     PORT_Assert(inKeyRecRep != NULL && inPKIStatus >= cmmfGranted &&
68                 inPKIStatus < cmmfNumPKIStatus);
69     if (inKeyRecRep == NULL) {
70         return SECFailure;
71     }
72 
73     return cmmf_PKIStatusInfoSetStatus(&inKeyRecRep->status,
74                                        inKeyRecRep->poolp,
75                                        inPKIStatus);
76 }
77 
78 SECStatus
CMMF_KeyRecRepContentSetNewSignCert(CMMFKeyRecRepContent * inKeyRecRep,CERTCertificate * inNewSignCert)79 CMMF_KeyRecRepContentSetNewSignCert(CMMFKeyRecRepContent *inKeyRecRep,
80                                     CERTCertificate *inNewSignCert)
81 {
82     PORT_Assert(inKeyRecRep != NULL && inNewSignCert != NULL);
83     if (inKeyRecRep == NULL || inNewSignCert == NULL) {
84         return SECFailure;
85     }
86     if (!inKeyRecRep->isDecoded && inKeyRecRep->newSigCert) {
87         CERT_DestroyCertificate(inKeyRecRep->newSigCert);
88     }
89     inKeyRecRep->isDecoded = PR_FALSE;
90     inKeyRecRep->newSigCert = CERT_DupCertificate(inNewSignCert);
91     return (inKeyRecRep->newSigCert == NULL) ? SECFailure : SECSuccess;
92 }
93 
94 SECStatus
CMMF_KeyRecRepContentSetCACerts(CMMFKeyRecRepContent * inKeyRecRep,CERTCertList * inCACerts)95 CMMF_KeyRecRepContentSetCACerts(CMMFKeyRecRepContent *inKeyRecRep,
96                                 CERTCertList *inCACerts)
97 {
98     SECStatus rv;
99     void *mark;
100 
101     PORT_Assert(inKeyRecRep != NULL && inCACerts != NULL);
102     if (inKeyRecRep == NULL || inCACerts == NULL) {
103         return SECFailure;
104     }
105     mark = PORT_ArenaMark(inKeyRecRep->poolp);
106     rv = cmmf_ExtractCertsFromList(inCACerts, inKeyRecRep->poolp,
107                                    &inKeyRecRep->caCerts);
108     if (rv != SECSuccess) {
109         PORT_ArenaRelease(inKeyRecRep->poolp, mark);
110     } else {
111         PORT_ArenaUnmark(inKeyRecRep->poolp, mark);
112     }
113     return rv;
114 }
115 
116 SECStatus
CMMF_KeyRecRepContentSetCertifiedKeyPair(CMMFKeyRecRepContent * inKeyRecRep,CERTCertificate * inCert,SECKEYPrivateKey * inPrivKey,SECKEYPublicKey * inPubKey)117 CMMF_KeyRecRepContentSetCertifiedKeyPair(CMMFKeyRecRepContent *inKeyRecRep,
118                                          CERTCertificate *inCert,
119                                          SECKEYPrivateKey *inPrivKey,
120                                          SECKEYPublicKey *inPubKey)
121 {
122     CMMFCertifiedKeyPair *keyPair;
123     CRMFEncryptedValue *dummy;
124     PLArenaPool *poolp;
125     void *mark;
126     SECStatus rv;
127 
128     PORT_Assert(inKeyRecRep != NULL &&
129                 inCert != NULL &&
130                 inPrivKey != NULL &&
131                 inPubKey != NULL);
132     if (inKeyRecRep == NULL ||
133         inCert == NULL ||
134         inPrivKey == NULL ||
135         inPubKey == NULL) {
136         return SECFailure;
137     }
138     poolp = inKeyRecRep->poolp;
139     mark = PORT_ArenaMark(poolp);
140     if (inKeyRecRep->keyPairHist == NULL) {
141         inKeyRecRep->keyPairHist = PORT_ArenaNewArray(poolp,
142                                                       CMMFCertifiedKeyPair *,
143                                                       (CMMF_MAX_KEY_PAIRS + 1));
144         if (inKeyRecRep->keyPairHist == NULL) {
145             goto loser;
146         }
147         inKeyRecRep->allocKeyPairs = CMMF_MAX_KEY_PAIRS;
148         inKeyRecRep->numKeyPairs = 0;
149     }
150 
151     if (inKeyRecRep->allocKeyPairs == inKeyRecRep->numKeyPairs) {
152         goto loser;
153     }
154 
155     keyPair = PORT_ArenaZNew(poolp, CMMFCertifiedKeyPair);
156     if (keyPair == NULL) {
157         goto loser;
158     }
159     rv = cmmf_CertOrEncCertSetCertificate(&keyPair->certOrEncCert,
160                                           poolp, inCert);
161     if (rv != SECSuccess) {
162         goto loser;
163     }
164     keyPair->privateKey = PORT_ArenaZNew(poolp, CRMFEncryptedValue);
165     if (keyPair->privateKey == NULL) {
166         goto loser;
167     }
168     dummy = crmf_create_encrypted_value_wrapped_privkey(inPrivKey, inPubKey,
169                                                         keyPair->privateKey);
170     PORT_Assert(dummy == keyPair->privateKey);
171     if (dummy != keyPair->privateKey) {
172         crmf_destroy_encrypted_value(dummy, PR_TRUE);
173         goto loser;
174     }
175     inKeyRecRep->keyPairHist[inKeyRecRep->numKeyPairs] = keyPair;
176     inKeyRecRep->numKeyPairs++;
177     inKeyRecRep->keyPairHist[inKeyRecRep->numKeyPairs] = NULL;
178     PORT_ArenaUnmark(poolp, mark);
179     return SECSuccess;
180 
181 loser:
182     PORT_ArenaRelease(poolp, mark);
183     return SECFailure;
184 }
185 
186 CMMFPKIStatus
CMMF_KeyRecRepContentGetPKIStatusInfoStatus(CMMFKeyRecRepContent * inKeyRecRep)187 CMMF_KeyRecRepContentGetPKIStatusInfoStatus(CMMFKeyRecRepContent *inKeyRecRep)
188 {
189     PORT_Assert(inKeyRecRep != NULL);
190     if (inKeyRecRep == NULL) {
191         return cmmfNoPKIStatus;
192     }
193     return cmmf_PKIStatusInfoGetStatus(&inKeyRecRep->status);
194 }
195 
196 CERTCertificate *
CMMF_KeyRecRepContentGetNewSignCert(CMMFKeyRecRepContent * inKeyRecRep)197 CMMF_KeyRecRepContentGetNewSignCert(CMMFKeyRecRepContent *inKeyRecRep)
198 {
199     PORT_Assert(inKeyRecRep != NULL);
200     if (inKeyRecRep == NULL ||
201         inKeyRecRep->newSigCert == NULL) {
202         return NULL;
203     }
204     /* newSigCert may not be a real certificate, it may be a hand decoded
205      * cert structure. This code makes sure we hand off a real, fully formed
206      * CERTCertificate to the caller. TODO: This should move into the decode
207      * portion so that we never wind up with a half formed CERTCertificate
208      * here. In this case the call would be to CERT_DupCertificate.
209      */
210     return CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
211                                    &inKeyRecRep->newSigCert->signatureWrap.data,
212                                    NULL, PR_FALSE, PR_TRUE);
213 }
214 
215 CERTCertList *
CMMF_KeyRecRepContentGetCACerts(CMMFKeyRecRepContent * inKeyRecRep)216 CMMF_KeyRecRepContentGetCACerts(CMMFKeyRecRepContent *inKeyRecRep)
217 {
218     PORT_Assert(inKeyRecRep != NULL);
219     if (inKeyRecRep == NULL || inKeyRecRep->caCerts == NULL) {
220         return NULL;
221     }
222     return cmmf_MakeCertList(inKeyRecRep->caCerts);
223 }
224 
225 int
CMMF_KeyRecRepContentGetNumKeyPairs(CMMFKeyRecRepContent * inKeyRecRep)226 CMMF_KeyRecRepContentGetNumKeyPairs(CMMFKeyRecRepContent *inKeyRecRep)
227 {
228     PORT_Assert(inKeyRecRep != NULL);
229     return (inKeyRecRep == NULL) ? 0 : inKeyRecRep->numKeyPairs;
230 }
231 
232 PRBool
cmmf_KeyRecRepContentIsValidIndex(CMMFKeyRecRepContent * inKeyRecRep,int inIndex)233 cmmf_KeyRecRepContentIsValidIndex(CMMFKeyRecRepContent *inKeyRecRep,
234                                   int inIndex)
235 {
236     int numKeyPairs = CMMF_KeyRecRepContentGetNumKeyPairs(inKeyRecRep);
237 
238     return (PRBool)(inIndex >= 0 && inIndex < numKeyPairs);
239 }
240 
241 CMMFCertifiedKeyPair *
CMMF_KeyRecRepContentGetCertKeyAtIndex(CMMFKeyRecRepContent * inKeyRecRep,int inIndex)242 CMMF_KeyRecRepContentGetCertKeyAtIndex(CMMFKeyRecRepContent *inKeyRecRep,
243                                        int inIndex)
244 {
245     CMMFCertifiedKeyPair *newKeyPair;
246     SECStatus rv;
247 
248     PORT_Assert(inKeyRecRep != NULL &&
249                 cmmf_KeyRecRepContentIsValidIndex(inKeyRecRep, inIndex));
250     if (inKeyRecRep == NULL ||
251         !cmmf_KeyRecRepContentIsValidIndex(inKeyRecRep, inIndex)) {
252         return NULL;
253     }
254     newKeyPair = PORT_ZNew(CMMFCertifiedKeyPair);
255     if (newKeyPair == NULL) {
256         return NULL;
257     }
258     rv = cmmf_CopyCertifiedKeyPair(NULL, newKeyPair,
259                                    inKeyRecRep->keyPairHist[inIndex]);
260     if (rv != SECSuccess) {
261         CMMF_DestroyCertifiedKeyPair(newKeyPair);
262         newKeyPair = NULL;
263     }
264     return newKeyPair;
265 }
266 
267 SECStatus
CMMF_CertifiedKeyPairUnwrapPrivKey(CMMFCertifiedKeyPair * inKeyPair,SECKEYPrivateKey * inPrivKey,SECItem * inNickName,PK11SlotInfo * inSlot,CERTCertDBHandle * inCertdb,SECKEYPrivateKey ** destPrivKey,void * wincx)268 CMMF_CertifiedKeyPairUnwrapPrivKey(CMMFCertifiedKeyPair *inKeyPair,
269                                    SECKEYPrivateKey *inPrivKey,
270                                    SECItem *inNickName,
271                                    PK11SlotInfo *inSlot,
272                                    CERTCertDBHandle *inCertdb,
273                                    SECKEYPrivateKey **destPrivKey,
274                                    void *wincx)
275 {
276     CERTCertificate *cert;
277     SECItem keyUsageValue = { siBuffer, NULL, 0 };
278     unsigned char keyUsage = 0x0;
279     SECKEYPublicKey *pubKey;
280     SECStatus rv;
281 
282     PORT_Assert(inKeyPair != NULL &&
283                 inPrivKey != NULL && inCertdb != NULL);
284     if (inKeyPair == NULL ||
285         inPrivKey == NULL ||
286         inKeyPair->privateKey == NULL ||
287         inCertdb == NULL) {
288         return SECFailure;
289     }
290 
291     cert = CMMF_CertifiedKeyPairGetCertificate(inKeyPair, inCertdb);
292     CERT_FindKeyUsageExtension(cert, &keyUsageValue);
293     if (keyUsageValue.data != NULL) {
294         keyUsage = keyUsageValue.data[3];
295         PORT_Free(keyUsageValue.data);
296     }
297     pubKey = CERT_ExtractPublicKey(cert);
298     rv = crmf_encrypted_value_unwrap_priv_key(NULL, inKeyPair->privateKey,
299                                               inPrivKey, pubKey,
300                                               inNickName, inSlot, keyUsage,
301                                               destPrivKey, wincx);
302     SECKEY_DestroyPublicKey(pubKey);
303     CERT_DestroyCertificate(cert);
304     return rv;
305 }
306 
307 PRBool
CMMF_KeyRecRepContentHasCACerts(CMMFKeyRecRepContent * inKeyRecRep)308 CMMF_KeyRecRepContentHasCACerts(CMMFKeyRecRepContent *inKeyRecRep)
309 {
310     PORT_Assert(inKeyRecRep != NULL);
311     if (inKeyRecRep == NULL) {
312         return PR_FALSE;
313     }
314     return (PRBool)(inKeyRecRep->caCerts != NULL &&
315                     inKeyRecRep->caCerts[0] != NULL);
316 }
317