crmfdec.c (10008B)
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 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 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 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 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 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 136 crmf_decode_process_keyagreement(CRMFCertReqMsg *inCertReqMsg) 137 { 138 return crmf_decode_process_popoprivkey(inCertReqMsg); 139 } 140 141 static SECStatus 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 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 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 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 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 * 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 * 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 }