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