Back to index

lightning-sunbird  0.9+nobinonly
crmfdec.c
Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 8 -*-*/
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the Netscape security libraries.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 
00039 #include "crmf.h"
00040 #include "crmfi.h"
00041 #include "secitem.h"
00042 
00043 static CRMFPOPChoice
00044 crmf_get_popchoice_from_der(SECItem *derPOP)
00045 {
00046     CRMFPOPChoice retChoice;
00047 
00048     switch (derPOP->data[0] & 0x0f) {
00049     case 0:
00050         retChoice = crmfRAVerified;
00051        break;
00052     case 1:
00053         retChoice = crmfSignature;
00054        break;
00055     case 2:
00056         retChoice = crmfKeyEncipherment;
00057        break;
00058     case 3:
00059         retChoice = crmfKeyAgreement;
00060        break;
00061     default:
00062         retChoice = crmfNoPOPChoice;
00063        break;
00064     }
00065     return retChoice;
00066 }
00067 
00068 static SECStatus
00069 crmf_decode_process_raverified(CRMFCertReqMsg *inCertReqMsg)
00070 {   
00071     CRMFProofOfPossession *pop;
00072     /* Just set up the structure so that the message structure
00073      * looks like one that was created using the API
00074      */
00075     pop = inCertReqMsg->pop;
00076     pop->popChoice.raVerified.data = NULL;
00077     pop->popChoice.raVerified.len  = 0;
00078     return SECSuccess;
00079 }
00080 
00081 static SECStatus
00082 crmf_decode_process_signature(CRMFCertReqMsg *inCertReqMsg)
00083 {
00084     PORT_Assert(inCertReqMsg->poolp);
00085     if (!inCertReqMsg->poolp) {
00086        PORT_SetError(SEC_ERROR_INVALID_ARGS);
00087        return SECFailure;
00088     }
00089     return SEC_ASN1Decode(inCertReqMsg->poolp,
00090                        &inCertReqMsg->pop->popChoice.signature,
00091                        CRMFPOPOSigningKeyTemplate, 
00092                        (const char*)inCertReqMsg->derPOP.data,
00093                        inCertReqMsg->derPOP.len);
00094 }
00095 
00096 static CRMFPOPOPrivKeyChoice
00097 crmf_get_messagechoice_from_der(SECItem *derPOP)
00098 {
00099     CRMFPOPOPrivKeyChoice retChoice;
00100 
00101     switch (derPOP->data[2] & 0x0f) {
00102     case 0:
00103         retChoice = crmfThisMessage;
00104        break;
00105     case 1:
00106         retChoice = crmfSubsequentMessage;
00107        break;
00108     case 2:
00109         retChoice = crmfDHMAC;
00110        break;
00111     default:
00112         retChoice = crmfNoMessage;
00113     }
00114     return retChoice;
00115 }
00116 
00117 static SECStatus
00118 crmf_decode_process_popoprivkey(CRMFCertReqMsg *inCertReqMsg)
00119 {
00120     /* We've got a union, so a pointer to one POPOPrivKey
00121      * struct is the same as having a pointer to the other 
00122      * one.
00123      */
00124     CRMFPOPOPrivKey *popoPrivKey = 
00125                     &inCertReqMsg->pop->popChoice.keyEncipherment;
00126     SECItem         *derPOP, privKeyDer;
00127     SECStatus        rv;
00128 
00129     derPOP = &inCertReqMsg->derPOP;
00130     popoPrivKey->messageChoice = crmf_get_messagechoice_from_der(derPOP);
00131     if (popoPrivKey->messageChoice == crmfNoMessage) {
00132         return SECFailure;
00133     }
00134     /* If we ever encounter BER encodings of this, we'll get in trouble*/
00135     switch (popoPrivKey->messageChoice) {
00136     case crmfThisMessage:
00137     case crmfDHMAC:
00138         privKeyDer.data = &derPOP->data[5];
00139        privKeyDer.len  = derPOP->len - 5;
00140        break;
00141     case crmfSubsequentMessage:
00142         privKeyDer.data = &derPOP->data[4];
00143        privKeyDer.len  = derPOP->len - 4;
00144        break;
00145     default:
00146         rv = SECFailure;
00147     }
00148 
00149     rv = SECITEM_CopyItem(inCertReqMsg->poolp, 
00150                        &popoPrivKey->message.subsequentMessage,
00151                        &privKeyDer);
00152 
00153     if (rv != SECSuccess) {
00154         return rv;
00155     }
00156 
00157     if (popoPrivKey->messageChoice == crmfThisMessage ||
00158        popoPrivKey->messageChoice == crmfDHMAC) {
00159 
00160         popoPrivKey->message.thisMessage.len = 
00161            CRMF_BYTES_TO_BITS(privKeyDer.len) - (int)derPOP->data[4];
00162         
00163     }
00164     return SECSuccess;    
00165 }
00166 
00167 static SECStatus
00168 crmf_decode_process_keyagreement(CRMFCertReqMsg *inCertReqMsg)
00169 {
00170     return crmf_decode_process_popoprivkey(inCertReqMsg);
00171 }
00172 
00173 static SECStatus
00174 crmf_decode_process_keyencipherment(CRMFCertReqMsg *inCertReqMsg)
00175 {
00176     SECStatus rv;
00177 
00178     rv = crmf_decode_process_popoprivkey(inCertReqMsg);
00179     if (rv != SECSuccess) {
00180         return rv;
00181     }
00182     if (inCertReqMsg->pop->popChoice.keyEncipherment.messageChoice == 
00183        crmfDHMAC) {
00184         /* Key Encipherment can not use the dhMAC option for
00185         * POPOPrivKey. 
00186         */
00187         return SECFailure;
00188     }
00189     return SECSuccess;
00190 }
00191 
00192 static SECStatus
00193 crmf_decode_process_pop(CRMFCertReqMsg *inCertReqMsg)
00194 {
00195      SECItem               *derPOP;
00196      PRArenaPool           *poolp;
00197      CRMFProofOfPossession *pop;
00198      void                  *mark;
00199      SECStatus              rv;
00200 
00201      derPOP = &inCertReqMsg->derPOP;
00202      poolp  = inCertReqMsg->poolp;
00203      if (derPOP->data == NULL) {
00204          /* There is no Proof of Possession field in this message. */
00205          return SECSuccess;
00206      }
00207      mark = PORT_ArenaMark(poolp);
00208      pop = PORT_ArenaZNew(poolp, CRMFProofOfPossession);
00209      if (pop == NULL) {
00210          goto loser;
00211      }
00212      pop->popUsed = crmf_get_popchoice_from_der(derPOP);
00213      if (pop->popUsed == crmfNoPOPChoice) {
00214          /* A bad encoding of CRMF.  Not a valid tag was given to the
00215          * Proof Of Possession field.
00216          */
00217          goto loser;
00218      }
00219      inCertReqMsg->pop = pop;
00220      switch (pop->popUsed) {
00221      case crmfRAVerified:
00222          rv = crmf_decode_process_raverified(inCertReqMsg);
00223         break;
00224      case crmfSignature:
00225          rv = crmf_decode_process_signature(inCertReqMsg);
00226         break;
00227      case crmfKeyEncipherment:
00228          rv = crmf_decode_process_keyencipherment(inCertReqMsg);
00229         break;
00230      case crmfKeyAgreement:
00231          rv = crmf_decode_process_keyagreement(inCertReqMsg);
00232         break;
00233      default:
00234          rv = SECFailure;
00235      }
00236      if (rv != SECSuccess) {
00237          goto loser;
00238      }
00239      PORT_ArenaUnmark(poolp, mark);
00240      return SECSuccess;
00241 
00242  loser:
00243      PORT_ArenaRelease(poolp, mark);
00244      inCertReqMsg->pop = NULL;
00245      return SECFailure;
00246      
00247 }
00248 
00249 static SECStatus
00250 crmf_decode_process_single_control(PRArenaPool *poolp, 
00251                                CRMFControl *inControl)
00252 {
00253     const SEC_ASN1Template *asn1Template = NULL;
00254 
00255     inControl->tag = SECOID_FindOIDTag(&inControl->derTag);
00256     asn1Template = crmf_get_pkiarchiveoptions_subtemplate(inControl);
00257 
00258     PORT_Assert (asn1Template != NULL);
00259     PORT_Assert (poolp != NULL);
00260     if (!asn1Template || !poolp) {
00261        PORT_SetError(SEC_ERROR_INVALID_ARGS);
00262        return SECFailure;
00263     }
00264     /* We've got a union, so passing a pointer to one element of the
00265      * union is the same as passing a pointer to any of the other
00266      * members of the union.
00267      */
00268     return SEC_ASN1Decode(poolp, &inControl->value.archiveOptions, 
00269                        asn1Template, (const char*)inControl->derValue.data,
00270                        inControl->derValue.len);
00271 }
00272 
00273 static SECStatus 
00274 crmf_decode_process_controls(CRMFCertReqMsg *inCertReqMsg)
00275 {
00276     int           i, numControls;
00277     SECStatus     rv;
00278     PRArenaPool  *poolp;
00279     CRMFControl **controls;
00280     
00281     numControls = CRMF_CertRequestGetNumControls(inCertReqMsg->certReq);
00282     controls = inCertReqMsg->certReq->controls;
00283     poolp    = inCertReqMsg->poolp;
00284     for (i=0; i < numControls; i++) {
00285         rv = crmf_decode_process_single_control(poolp, controls[i]);
00286        if (rv != SECSuccess) {
00287            return SECFailure;
00288        }
00289     }
00290     return SECSuccess;
00291 }
00292 
00293 static SECStatus
00294 crmf_decode_process_single_reqmsg(CRMFCertReqMsg *inCertReqMsg)
00295 {
00296     SECStatus rv;
00297 
00298     rv = crmf_decode_process_pop(inCertReqMsg);
00299     if (rv != SECSuccess) {
00300         goto loser;
00301     }
00302 
00303     rv = crmf_decode_process_controls(inCertReqMsg);
00304     if (rv != SECSuccess) {
00305         goto loser;
00306     }
00307     inCertReqMsg->certReq->certTemplate.numExtensions = 
00308         CRMF_CertRequestGetNumberOfExtensions(inCertReqMsg->certReq);
00309     inCertReqMsg->isDecoded = PR_TRUE;
00310     rv = SECSuccess;
00311  loser:
00312     return rv;
00313 }
00314 
00315 CRMFCertReqMsg*
00316 CRMF_CreateCertReqMsgFromDER (const char * buf, long len)
00317 {
00318     PRArenaPool    *poolp;
00319     CRMFCertReqMsg *certReqMsg;
00320     SECStatus       rv;
00321 
00322     poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE);
00323     if (poolp == NULL) {
00324         goto loser;
00325     }
00326     certReqMsg = PORT_ArenaZNew (poolp, CRMFCertReqMsg);
00327     if (certReqMsg == NULL) {
00328         goto loser;
00329     }
00330     certReqMsg->poolp = poolp;
00331     rv = SEC_ASN1Decode(poolp, certReqMsg, CRMFCertReqMsgTemplate, buf, len);
00332     if (rv != SECSuccess) {
00333         goto loser;
00334     }
00335 
00336     rv = crmf_decode_process_single_reqmsg(certReqMsg);
00337     if (rv != SECSuccess) {
00338         goto loser;
00339     }
00340 
00341     return certReqMsg;
00342  loser:
00343     if (poolp != NULL) {
00344         PORT_FreeArena(poolp, PR_FALSE);
00345     }
00346     return NULL;
00347 }
00348 
00349 CRMFCertReqMessages*
00350 CRMF_CreateCertReqMessagesFromDER(const char *buf, long len)
00351 {
00352     long                 arenaSize;
00353     int                  i;
00354     SECStatus            rv;
00355     PRArenaPool         *poolp;
00356     CRMFCertReqMessages *certReqMsgs;
00357 
00358     PORT_Assert (buf != NULL);
00359     /* Wanna make sure the arena is big enough to store all of the requests
00360      * coming in.  We'll guestimate according to the length of the buffer.
00361      */
00362     arenaSize = len + len/2;
00363     poolp = PORT_NewArena(arenaSize);
00364     if (poolp == NULL) {
00365         return NULL;
00366     }
00367     certReqMsgs = PORT_ArenaZNew(poolp, CRMFCertReqMessages);
00368     if (certReqMsgs == NULL) {
00369         goto loser;
00370     }
00371     certReqMsgs->poolp = poolp;
00372     rv = SEC_ASN1Decode(poolp, certReqMsgs, CRMFCertReqMessagesTemplate,
00373                      buf, len);
00374     if (rv != SECSuccess) {
00375         goto loser;
00376     }
00377     for (i=0; certReqMsgs->messages[i] != NULL; i++) {
00378         /* The sub-routines expect the individual messages to have 
00379         * an arena.  We'll give them one temporarily.
00380         */
00381         certReqMsgs->messages[i]->poolp = poolp;
00382         rv = crmf_decode_process_single_reqmsg(certReqMsgs->messages[i]);
00383        if (rv != SECSuccess) {
00384            goto loser;
00385        }
00386         certReqMsgs->messages[i]->poolp = NULL;
00387     }
00388     return certReqMsgs;
00389 
00390  loser:
00391     PORT_FreeArena(poolp, PR_FALSE);
00392     return NULL;
00393 }