PageRenderTime 32ms CodeModel.GetById 14ms app.highlight 15ms RepoModel.GetById 1ms app.codeStats 0ms

/security/nss/lib/crmf/crmfdec.c

http://github.com/zpao/v8monkey
C | 395 lines | 297 code | 37 blank | 61 comment | 56 complexity | 9d1cabc94e1f3481d70cd43d4123eeea MD5 | raw file
  1/* -*- Mode: C; tab-width: 8 -*-*/
  2/* ***** BEGIN LICENSE BLOCK *****
  3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  4 *
  5 * The contents of this file are subject to the Mozilla Public License Version
  6 * 1.1 (the "License"); you may not use this file except in compliance with
  7 * the License. You may obtain a copy of the License at
  8 * http://www.mozilla.org/MPL/
  9 *
 10 * Software distributed under the License is distributed on an "AS IS" basis,
 11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 12 * for the specific language governing rights and limitations under the
 13 * License.
 14 *
 15 * The Original Code is the Netscape security libraries.
 16 *
 17 * The Initial Developer of the Original Code is
 18 * Netscape Communications Corporation.
 19 * Portions created by the Initial Developer are Copyright (C) 1994-2000
 20 * the Initial Developer. All Rights Reserved.
 21 *
 22 * Contributor(s):
 23 *
 24 * Alternatively, the contents of this file may be used under the terms of
 25 * either the GNU General Public License Version 2 or later (the "GPL"), or
 26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 27 * in which case the provisions of the GPL or the LGPL are applicable instead
 28 * of those above. If you wish to allow use of your version of this file only
 29 * under the terms of either the GPL or the LGPL, and not to allow others to
 30 * use your version of this file under the terms of the MPL, indicate your
 31 * decision by deleting the provisions above and replace them with the notice
 32 * and other provisions required by the GPL or the LGPL. If you do not delete
 33 * the provisions above, a recipient may use your version of this file under
 34 * the terms of any one of the MPL, the GPL or the LGPL.
 35 *
 36 * ***** END LICENSE BLOCK ***** */
 37
 38
 39#include "crmf.h"
 40#include "crmfi.h"
 41#include "secitem.h"
 42
 43static CRMFPOPChoice
 44crmf_get_popchoice_from_der(SECItem *derPOP)
 45{
 46    CRMFPOPChoice retChoice;
 47
 48    switch (derPOP->data[0] & 0x0f) {
 49    case 0:
 50        retChoice = crmfRAVerified;
 51	break;
 52    case 1:
 53        retChoice = crmfSignature;
 54	break;
 55    case 2:
 56        retChoice = crmfKeyEncipherment;
 57	break;
 58    case 3:
 59        retChoice = crmfKeyAgreement;
 60	break;
 61    default:
 62        retChoice = crmfNoPOPChoice;
 63	break;
 64    }
 65    return retChoice;
 66}
 67
 68static SECStatus
 69crmf_decode_process_raverified(CRMFCertReqMsg *inCertReqMsg)
 70{   
 71    CRMFProofOfPossession *pop;
 72    /* Just set up the structure so that the message structure
 73     * looks like one that was created using the API
 74     */
 75    pop = inCertReqMsg->pop;
 76    pop->popChoice.raVerified.data = NULL;
 77    pop->popChoice.raVerified.len  = 0;
 78    return SECSuccess;
 79}
 80
 81static SECStatus
 82crmf_decode_process_signature(CRMFCertReqMsg *inCertReqMsg)
 83{
 84    PORT_Assert(inCertReqMsg->poolp);
 85    if (!inCertReqMsg->poolp) {
 86    	PORT_SetError(SEC_ERROR_INVALID_ARGS);
 87	return SECFailure;
 88    }
 89    return SEC_ASN1Decode(inCertReqMsg->poolp,
 90			  &inCertReqMsg->pop->popChoice.signature,
 91			  CRMFPOPOSigningKeyTemplate, 
 92			  (const char*)inCertReqMsg->derPOP.data,
 93			  inCertReqMsg->derPOP.len);
 94}
 95
 96static CRMFPOPOPrivKeyChoice
 97crmf_get_messagechoice_from_der(SECItem *derPOP)
 98{
 99    CRMFPOPOPrivKeyChoice retChoice;
100
101    switch (derPOP->data[2] & 0x0f) {
102    case 0:
103        retChoice = crmfThisMessage;
104	break;
105    case 1:
106        retChoice = crmfSubsequentMessage;
107	break;
108    case 2:
109        retChoice = crmfDHMAC;
110	break;
111    default:
112        retChoice = crmfNoMessage;
113    }
114    return retChoice;
115}
116
117static SECStatus
118crmf_decode_process_popoprivkey(CRMFCertReqMsg *inCertReqMsg)
119{
120    /* We've got a union, so a pointer to one POPOPrivKey
121     * struct is the same as having a pointer to the other 
122     * one.
123     */
124    CRMFPOPOPrivKey *popoPrivKey = 
125                    &inCertReqMsg->pop->popChoice.keyEncipherment;
126    SECItem         *derPOP, privKeyDer;
127    SECStatus        rv;
128
129    derPOP = &inCertReqMsg->derPOP;
130    popoPrivKey->messageChoice = crmf_get_messagechoice_from_der(derPOP);
131    if (popoPrivKey->messageChoice == crmfNoMessage) {
132        return SECFailure;
133    }
134    /* If we ever encounter BER encodings of this, we'll get in trouble*/
135    switch (popoPrivKey->messageChoice) {
136    case crmfThisMessage:
137    case crmfDHMAC:
138        privKeyDer.type = derPOP->type;
139        privKeyDer.data = &derPOP->data[5];
140	privKeyDer.len  = derPOP->len - 5;
141	break;
142    case crmfSubsequentMessage:
143        privKeyDer.type = derPOP->type;
144        privKeyDer.data = &derPOP->data[4];
145	privKeyDer.len  = derPOP->len - 4;
146	break;
147    default:
148        return SECFailure;
149    }
150
151    rv = SECITEM_CopyItem(inCertReqMsg->poolp, 
152			  &popoPrivKey->message.subsequentMessage,
153			  &privKeyDer);
154
155    if (rv != SECSuccess) {
156        return rv;
157    }
158
159    if (popoPrivKey->messageChoice == crmfThisMessage ||
160	popoPrivKey->messageChoice == crmfDHMAC) {
161
162        popoPrivKey->message.thisMessage.len = 
163	    CRMF_BYTES_TO_BITS(privKeyDer.len) - (int)derPOP->data[4];
164        
165    }
166    return SECSuccess;    
167}
168
169static SECStatus
170crmf_decode_process_keyagreement(CRMFCertReqMsg *inCertReqMsg)
171{
172    return crmf_decode_process_popoprivkey(inCertReqMsg);
173}
174
175static SECStatus
176crmf_decode_process_keyencipherment(CRMFCertReqMsg *inCertReqMsg)
177{
178    SECStatus rv;
179
180    rv = crmf_decode_process_popoprivkey(inCertReqMsg);
181    if (rv != SECSuccess) {
182        return rv;
183    }
184    if (inCertReqMsg->pop->popChoice.keyEncipherment.messageChoice == 
185	crmfDHMAC) {
186        /* Key Encipherment can not use the dhMAC option for
187	 * POPOPrivKey. 
188	 */
189        return SECFailure;
190    }
191    return SECSuccess;
192}
193
194static SECStatus
195crmf_decode_process_pop(CRMFCertReqMsg *inCertReqMsg)
196{
197     SECItem               *derPOP;
198     PRArenaPool           *poolp;
199     CRMFProofOfPossession *pop;
200     void                  *mark;
201     SECStatus              rv;
202
203     derPOP = &inCertReqMsg->derPOP;
204     poolp  = inCertReqMsg->poolp;
205     if (derPOP->data == NULL) {
206         /* There is no Proof of Possession field in this message. */
207         return SECSuccess;
208     }
209     mark = PORT_ArenaMark(poolp);
210     pop = PORT_ArenaZNew(poolp, CRMFProofOfPossession);
211     if (pop == NULL) {
212         goto loser;
213     }
214     pop->popUsed = crmf_get_popchoice_from_der(derPOP);
215     if (pop->popUsed == crmfNoPOPChoice) {
216         /* A bad encoding of CRMF.  Not a valid tag was given to the
217	  * Proof Of Possession field.
218	  */
219         goto loser;
220     }
221     inCertReqMsg->pop = pop;
222     switch (pop->popUsed) {
223     case crmfRAVerified:
224         rv = crmf_decode_process_raverified(inCertReqMsg);
225	 break;
226     case crmfSignature:
227         rv = crmf_decode_process_signature(inCertReqMsg);
228	 break;
229     case crmfKeyEncipherment:
230         rv = crmf_decode_process_keyencipherment(inCertReqMsg);
231	 break;
232     case crmfKeyAgreement:
233         rv = crmf_decode_process_keyagreement(inCertReqMsg);
234	 break;
235     default:
236         rv = SECFailure;
237     }
238     if (rv != SECSuccess) {
239         goto loser;
240     }
241     PORT_ArenaUnmark(poolp, mark);
242     return SECSuccess;
243
244 loser:
245     PORT_ArenaRelease(poolp, mark);
246     inCertReqMsg->pop = NULL;
247     return SECFailure;
248     
249}
250
251static SECStatus
252crmf_decode_process_single_control(PRArenaPool *poolp, 
253				   CRMFControl *inControl)
254{
255    const SEC_ASN1Template *asn1Template = NULL;
256
257    inControl->tag = SECOID_FindOIDTag(&inControl->derTag);
258    asn1Template = crmf_get_pkiarchiveoptions_subtemplate(inControl);
259
260    PORT_Assert (asn1Template != NULL);
261    PORT_Assert (poolp != NULL);
262    if (!asn1Template || !poolp) {
263    	PORT_SetError(SEC_ERROR_INVALID_ARGS);
264	return SECFailure;
265    }
266    /* We've got a union, so passing a pointer to one element of the
267     * union is the same as passing a pointer to any of the other
268     * members of the union.
269     */
270    return SEC_ASN1Decode(poolp, &inControl->value.archiveOptions, 
271			  asn1Template, (const char*)inControl->derValue.data,
272			  inControl->derValue.len);
273}
274
275static SECStatus 
276crmf_decode_process_controls(CRMFCertReqMsg *inCertReqMsg)
277{
278    int           i, numControls;
279    SECStatus     rv;
280    PRArenaPool  *poolp;
281    CRMFControl **controls;
282    
283    numControls = CRMF_CertRequestGetNumControls(inCertReqMsg->certReq);
284    controls = inCertReqMsg->certReq->controls;
285    poolp    = inCertReqMsg->poolp;
286    for (i=0; i < numControls; i++) {
287        rv = crmf_decode_process_single_control(poolp, controls[i]);
288	if (rv != SECSuccess) {
289	    return SECFailure;
290	}
291    }
292    return SECSuccess;
293}
294
295static SECStatus
296crmf_decode_process_single_reqmsg(CRMFCertReqMsg *inCertReqMsg)
297{
298    SECStatus rv;
299
300    rv = crmf_decode_process_pop(inCertReqMsg);
301    if (rv != SECSuccess) {
302        goto loser;
303    }
304
305    rv = crmf_decode_process_controls(inCertReqMsg);
306    if (rv != SECSuccess) {
307        goto loser;
308    }
309    inCertReqMsg->certReq->certTemplate.numExtensions = 
310        CRMF_CertRequestGetNumberOfExtensions(inCertReqMsg->certReq);
311    inCertReqMsg->isDecoded = PR_TRUE;
312    rv = SECSuccess;
313 loser:
314    return rv;
315}
316
317CRMFCertReqMsg*
318CRMF_CreateCertReqMsgFromDER (const char * buf, long len)
319{
320    PRArenaPool    *poolp;
321    CRMFCertReqMsg *certReqMsg;
322    SECStatus       rv;
323
324    poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE);
325    if (poolp == NULL) {
326        goto loser;
327    }
328    certReqMsg = PORT_ArenaZNew (poolp, CRMFCertReqMsg);
329    if (certReqMsg == NULL) {
330        goto loser;
331    }
332    certReqMsg->poolp = poolp;
333    rv = SEC_ASN1Decode(poolp, certReqMsg, CRMFCertReqMsgTemplate, buf, len);
334    if (rv != SECSuccess) {
335        goto loser;
336    }
337
338    rv = crmf_decode_process_single_reqmsg(certReqMsg);
339    if (rv != SECSuccess) {
340        goto loser;
341    }
342
343    return certReqMsg;
344 loser:
345    if (poolp != NULL) {
346        PORT_FreeArena(poolp, PR_FALSE);
347    }
348    return NULL;
349}
350
351CRMFCertReqMessages*
352CRMF_CreateCertReqMessagesFromDER(const char *buf, long len)
353{
354    long                 arenaSize;
355    int                  i;
356    SECStatus            rv;
357    PRArenaPool         *poolp;
358    CRMFCertReqMessages *certReqMsgs;
359
360    PORT_Assert (buf != NULL);
361    /* Wanna make sure the arena is big enough to store all of the requests
362     * coming in.  We'll guestimate according to the length of the buffer.
363     */
364    arenaSize = len + len/2;
365    poolp = PORT_NewArena(arenaSize);
366    if (poolp == NULL) {
367        return NULL;
368    }
369    certReqMsgs = PORT_ArenaZNew(poolp, CRMFCertReqMessages);
370    if (certReqMsgs == NULL) {
371        goto loser;
372    }
373    certReqMsgs->poolp = poolp;
374    rv = SEC_ASN1Decode(poolp, certReqMsgs, CRMFCertReqMessagesTemplate,
375			buf, len);
376    if (rv != SECSuccess) {
377        goto loser;
378    }
379    for (i=0; certReqMsgs->messages[i] != NULL; i++) {
380        /* The sub-routines expect the individual messages to have 
381	 * an arena.  We'll give them one temporarily.
382	 */
383        certReqMsgs->messages[i]->poolp = poolp;
384        rv = crmf_decode_process_single_reqmsg(certReqMsgs->messages[i]);
385	if (rv != SECSuccess) {
386	    goto loser;
387	}
388        certReqMsgs->messages[i]->poolp = NULL;
389    }
390    return certReqMsgs;
391
392 loser:
393    PORT_FreeArena(poolp, PR_FALSE);
394    return NULL;
395}