security/nss/lib/crmf/crmfdec.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial