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 #include "crmf.h"
7 #include "crmfi.h"
8 #include "secitem.h"
9 
10 static CRMFPOPChoice
crmf_get_popchoice_from_der(SECItem * derPOP)11 crmf_get_popchoice_from_der(SECItem *derPOP)
12 {
13     CRMFPOPChoice retChoice;
14 
15     switch (derPOP->data[0] & 0x0f) {
16         case 0:
17             retChoice = crmfRAVerified;
18             break;
19         case 1:
20             retChoice = crmfSignature;
21             break;
22         case 2:
23             retChoice = crmfKeyEncipherment;
24             break;
25         case 3:
26             retChoice = crmfKeyAgreement;
27             break;
28         default:
29             retChoice = crmfNoPOPChoice;
30             break;
31     }
32     return retChoice;
33 }
34 
35 static SECStatus
crmf_decode_process_raverified(CRMFCertReqMsg * inCertReqMsg)36 crmf_decode_process_raverified(CRMFCertReqMsg *inCertReqMsg)
37 {
38     CRMFProofOfPossession *pop;
39     /* Just set up the structure so that the message structure
40      * looks like one that was created using the API
41      */
42     pop = inCertReqMsg->pop;
43     pop->popChoice.raVerified.data = NULL;
44     pop->popChoice.raVerified.len = 0;
45     return SECSuccess;
46 }
47 
48 static SECStatus
crmf_decode_process_signature(CRMFCertReqMsg * inCertReqMsg)49 crmf_decode_process_signature(CRMFCertReqMsg *inCertReqMsg)
50 {
51     PORT_Assert(inCertReqMsg->poolp);
52     if (!inCertReqMsg->poolp) {
53         PORT_SetError(SEC_ERROR_INVALID_ARGS);
54         return SECFailure;
55     }
56     return SEC_ASN1Decode(inCertReqMsg->poolp,
57                           &inCertReqMsg->pop->popChoice.signature,
58                           CRMFPOPOSigningKeyTemplate,
59                           (const char *)inCertReqMsg->derPOP.data,
60                           inCertReqMsg->derPOP.len);
61 }
62 
63 static CRMFPOPOPrivKeyChoice
crmf_get_messagechoice_from_der(SECItem * derPOP)64 crmf_get_messagechoice_from_der(SECItem *derPOP)
65 {
66     CRMFPOPOPrivKeyChoice retChoice;
67 
68     switch (derPOP->data[2] & 0x0f) {
69         case 0:
70             retChoice = crmfThisMessage;
71             break;
72         case 1:
73             retChoice = crmfSubsequentMessage;
74             break;
75         case 2:
76             retChoice = crmfDHMAC;
77             break;
78         default:
79             retChoice = crmfNoMessage;
80     }
81     return retChoice;
82 }
83 
84 static SECStatus
crmf_decode_process_popoprivkey(CRMFCertReqMsg * inCertReqMsg)85 crmf_decode_process_popoprivkey(CRMFCertReqMsg *inCertReqMsg)
86 {
87     /* We've got a union, so a pointer to one POPOPrivKey
88      * struct is the same as having a pointer to the other
89      * one.
90      */
91     CRMFPOPOPrivKey *popoPrivKey =
92         &inCertReqMsg->pop->popChoice.keyEncipherment;
93     SECItem *derPOP, privKeyDer;
94     SECStatus rv;
95 
96     derPOP = &inCertReqMsg->derPOP;
97     popoPrivKey->messageChoice = crmf_get_messagechoice_from_der(derPOP);
98     if (popoPrivKey->messageChoice == crmfNoMessage) {
99         return SECFailure;
100     }
101     /* If we ever encounter BER encodings of this, we'll get in trouble*/
102     switch (popoPrivKey->messageChoice) {
103         case crmfThisMessage:
104         case crmfDHMAC:
105             privKeyDer.type = derPOP->type;
106             privKeyDer.data = &derPOP->data[5];
107             privKeyDer.len = derPOP->len - 5;
108             break;
109         case crmfSubsequentMessage:
110             privKeyDer.type = derPOP->type;
111             privKeyDer.data = &derPOP->data[4];
112             privKeyDer.len = derPOP->len - 4;
113             break;
114         default:
115             return SECFailure;
116     }
117 
118     rv = SECITEM_CopyItem(inCertReqMsg->poolp,
119                           &popoPrivKey->message.subsequentMessage,
120                           &privKeyDer);
121 
122     if (rv != SECSuccess) {
123         return rv;
124     }
125 
126     if (popoPrivKey->messageChoice == crmfThisMessage ||
127         popoPrivKey->messageChoice == crmfDHMAC) {
128 
129         popoPrivKey->message.thisMessage.len =
130             CRMF_BYTES_TO_BITS(privKeyDer.len) - (int)derPOP->data[4];
131     }
132     return SECSuccess;
133 }
134 
135 static SECStatus
crmf_decode_process_keyagreement(CRMFCertReqMsg * inCertReqMsg)136 crmf_decode_process_keyagreement(CRMFCertReqMsg *inCertReqMsg)
137 {
138     return crmf_decode_process_popoprivkey(inCertReqMsg);
139 }
140 
141 static SECStatus
crmf_decode_process_keyencipherment(CRMFCertReqMsg * inCertReqMsg)142 crmf_decode_process_keyencipherment(CRMFCertReqMsg *inCertReqMsg)
143 {
144     SECStatus rv;
145 
146     rv = crmf_decode_process_popoprivkey(inCertReqMsg);
147     if (rv != SECSuccess) {
148         return rv;
149     }
150     if (inCertReqMsg->pop->popChoice.keyEncipherment.messageChoice ==
151         crmfDHMAC) {
152         /* Key Encipherment can not use the dhMAC option for
153          * POPOPrivKey.
154          */
155         return SECFailure;
156     }
157     return SECSuccess;
158 }
159 
160 static SECStatus
crmf_decode_process_pop(CRMFCertReqMsg * inCertReqMsg)161 crmf_decode_process_pop(CRMFCertReqMsg *inCertReqMsg)
162 {
163     SECItem *derPOP;
164     PLArenaPool *poolp;
165     CRMFProofOfPossession *pop;
166     void *mark;
167     SECStatus rv;
168 
169     derPOP = &inCertReqMsg->derPOP;
170     poolp = inCertReqMsg->poolp;
171     if (derPOP->data == NULL) {
172         /* There is no Proof of Possession field in this message. */
173         return SECSuccess;
174     }
175     mark = PORT_ArenaMark(poolp);
176     pop = PORT_ArenaZNew(poolp, CRMFProofOfPossession);
177     if (pop == NULL) {
178         goto loser;
179     }
180     pop->popUsed = crmf_get_popchoice_from_der(derPOP);
181     if (pop->popUsed == crmfNoPOPChoice) {
182         /* A bad encoding of CRMF.  Not a valid tag was given to the
183          * Proof Of Possession field.
184          */
185         goto loser;
186     }
187     inCertReqMsg->pop = pop;
188     switch (pop->popUsed) {
189         case crmfRAVerified:
190             rv = crmf_decode_process_raverified(inCertReqMsg);
191             break;
192         case crmfSignature:
193             rv = crmf_decode_process_signature(inCertReqMsg);
194             break;
195         case crmfKeyEncipherment:
196             rv = crmf_decode_process_keyencipherment(inCertReqMsg);
197             break;
198         case crmfKeyAgreement:
199             rv = crmf_decode_process_keyagreement(inCertReqMsg);
200             break;
201         default:
202             rv = SECFailure;
203     }
204     if (rv != SECSuccess) {
205         goto loser;
206     }
207     PORT_ArenaUnmark(poolp, mark);
208     return SECSuccess;
209 
210 loser:
211     PORT_ArenaRelease(poolp, mark);
212     inCertReqMsg->pop = NULL;
213     return SECFailure;
214 }
215 
216 static SECStatus
crmf_decode_process_single_control(PLArenaPool * poolp,CRMFControl * inControl)217 crmf_decode_process_single_control(PLArenaPool *poolp,
218                                    CRMFControl *inControl)
219 {
220     const SEC_ASN1Template *asn1Template = NULL;
221 
222     inControl->tag = SECOID_FindOIDTag(&inControl->derTag);
223     asn1Template = crmf_get_pkiarchiveoptions_subtemplate(inControl);
224 
225     PORT_Assert(asn1Template != NULL);
226     PORT_Assert(poolp != NULL);
227     if (!asn1Template || !poolp) {
228         PORT_SetError(SEC_ERROR_INVALID_ARGS);
229         return SECFailure;
230     }
231     /* We've got a union, so passing a pointer to one element of the
232      * union is the same as passing a pointer to any of the other
233      * members of the union.
234      */
235     return SEC_ASN1Decode(poolp, &inControl->value.archiveOptions,
236                           asn1Template, (const char *)inControl->derValue.data,
237                           inControl->derValue.len);
238 }
239 
240 static SECStatus
crmf_decode_process_controls(CRMFCertReqMsg * inCertReqMsg)241 crmf_decode_process_controls(CRMFCertReqMsg *inCertReqMsg)
242 {
243     int i, numControls;
244     SECStatus rv;
245     PLArenaPool *poolp;
246     CRMFControl **controls;
247 
248     numControls = CRMF_CertRequestGetNumControls(inCertReqMsg->certReq);
249     controls = inCertReqMsg->certReq->controls;
250     poolp = inCertReqMsg->poolp;
251     for (i = 0; i < numControls; i++) {
252         rv = crmf_decode_process_single_control(poolp, controls[i]);
253         if (rv != SECSuccess) {
254             return SECFailure;
255         }
256     }
257     return SECSuccess;
258 }
259 
260 static SECStatus
crmf_decode_process_single_reqmsg(CRMFCertReqMsg * inCertReqMsg)261 crmf_decode_process_single_reqmsg(CRMFCertReqMsg *inCertReqMsg)
262 {
263     SECStatus rv;
264 
265     rv = crmf_decode_process_pop(inCertReqMsg);
266     if (rv != SECSuccess) {
267         goto loser;
268     }
269 
270     rv = crmf_decode_process_controls(inCertReqMsg);
271     if (rv != SECSuccess) {
272         goto loser;
273     }
274     inCertReqMsg->certReq->certTemplate.numExtensions =
275         CRMF_CertRequestGetNumberOfExtensions(inCertReqMsg->certReq);
276     inCertReqMsg->isDecoded = PR_TRUE;
277     rv = SECSuccess;
278 loser:
279     return rv;
280 }
281 
282 CRMFCertReqMsg *
CRMF_CreateCertReqMsgFromDER(const char * buf,long len)283 CRMF_CreateCertReqMsgFromDER(const char *buf, long len)
284 {
285     PLArenaPool *poolp;
286     CRMFCertReqMsg *certReqMsg;
287     SECStatus rv;
288 
289     poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE);
290     if (poolp == NULL) {
291         goto loser;
292     }
293     certReqMsg = PORT_ArenaZNew(poolp, CRMFCertReqMsg);
294     if (certReqMsg == NULL) {
295         goto loser;
296     }
297     certReqMsg->poolp = poolp;
298     rv = SEC_ASN1Decode(poolp, certReqMsg, CRMFCertReqMsgTemplate, buf, len);
299     if (rv != SECSuccess) {
300         goto loser;
301     }
302 
303     rv = crmf_decode_process_single_reqmsg(certReqMsg);
304     if (rv != SECSuccess) {
305         goto loser;
306     }
307 
308     return certReqMsg;
309 loser:
310     if (poolp != NULL) {
311         PORT_FreeArena(poolp, PR_FALSE);
312     }
313     return NULL;
314 }
315 
316 CRMFCertReqMessages *
CRMF_CreateCertReqMessagesFromDER(const char * buf,long len)317 CRMF_CreateCertReqMessagesFromDER(const char *buf, long len)
318 {
319     long arenaSize;
320     int i;
321     SECStatus rv;
322     PLArenaPool *poolp;
323     CRMFCertReqMessages *certReqMsgs;
324 
325     PORT_Assert(buf != NULL);
326     /* Wanna make sure the arena is big enough to store all of the requests
327      * coming in.  We'll guestimate according to the length of the buffer.
328      */
329     arenaSize = len + len / 2;
330     poolp = PORT_NewArena(arenaSize);
331     if (poolp == NULL) {
332         return NULL;
333     }
334     certReqMsgs = PORT_ArenaZNew(poolp, CRMFCertReqMessages);
335     if (certReqMsgs == NULL) {
336         goto loser;
337     }
338     certReqMsgs->poolp = poolp;
339     rv = SEC_ASN1Decode(poolp, certReqMsgs, CRMFCertReqMessagesTemplate,
340                         buf, len);
341     if (rv != SECSuccess) {
342         goto loser;
343     }
344     for (i = 0; certReqMsgs->messages[i] != NULL; i++) {
345         /* The sub-routines expect the individual messages to have
346          * an arena.  We'll give them one temporarily.
347          */
348         certReqMsgs->messages[i]->poolp = poolp;
349         rv = crmf_decode_process_single_reqmsg(certReqMsgs->messages[i]);
350         if (rv != SECSuccess) {
351             goto loser;
352         }
353         certReqMsgs->messages[i]->poolp = NULL;
354     }
355     return certReqMsgs;
356 
357 loser:
358     PORT_FreeArena(poolp, PR_FALSE);
359     return NULL;
360 }
361