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