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
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 "secasn1.h" |
michael@0 | 10 | #include "keyhi.h" |
michael@0 | 11 | #include "cryptohi.h" |
michael@0 | 12 | |
michael@0 | 13 | #define CRMF_DEFAULT_ALLOC_SIZE 1024 |
michael@0 | 14 | |
michael@0 | 15 | SECStatus |
michael@0 | 16 | crmf_init_encoder_callback_arg (struct crmfEncoderArg *encoderArg, |
michael@0 | 17 | SECItem *derDest) |
michael@0 | 18 | { |
michael@0 | 19 | derDest->data = PORT_ZNewArray(unsigned char, CRMF_DEFAULT_ALLOC_SIZE); |
michael@0 | 20 | if (derDest->data == NULL) { |
michael@0 | 21 | return SECFailure; |
michael@0 | 22 | } |
michael@0 | 23 | derDest->len = 0; |
michael@0 | 24 | encoderArg->allocatedLen = CRMF_DEFAULT_ALLOC_SIZE; |
michael@0 | 25 | encoderArg->buffer = derDest; |
michael@0 | 26 | return SECSuccess; |
michael@0 | 27 | |
michael@0 | 28 | } |
michael@0 | 29 | |
michael@0 | 30 | /* Caller should release or unmark the pool, instead of doing it here. |
michael@0 | 31 | ** But there are NO callers of this function at present... |
michael@0 | 32 | */ |
michael@0 | 33 | SECStatus |
michael@0 | 34 | CRMF_CertReqMsgSetRAVerifiedPOP(CRMFCertReqMsg *inCertReqMsg) |
michael@0 | 35 | { |
michael@0 | 36 | SECItem *dummy; |
michael@0 | 37 | CRMFProofOfPossession *pop; |
michael@0 | 38 | PLArenaPool *poolp; |
michael@0 | 39 | void *mark; |
michael@0 | 40 | |
michael@0 | 41 | PORT_Assert(inCertReqMsg != NULL && inCertReqMsg->pop == NULL); |
michael@0 | 42 | poolp = inCertReqMsg->poolp; |
michael@0 | 43 | mark = PORT_ArenaMark(poolp); |
michael@0 | 44 | if (CRMF_CertReqMsgGetPOPType(inCertReqMsg) != crmfNoPOPChoice) { |
michael@0 | 45 | return SECFailure; |
michael@0 | 46 | } |
michael@0 | 47 | pop = PORT_ArenaZNew(poolp, CRMFProofOfPossession); |
michael@0 | 48 | if (pop == NULL) { |
michael@0 | 49 | goto loser; |
michael@0 | 50 | } |
michael@0 | 51 | pop->popUsed = crmfRAVerified; |
michael@0 | 52 | pop->popChoice.raVerified.data = NULL; |
michael@0 | 53 | pop->popChoice.raVerified.len = 0; |
michael@0 | 54 | inCertReqMsg->pop = pop; |
michael@0 | 55 | dummy = SEC_ASN1EncodeItem(poolp, &(inCertReqMsg->derPOP), |
michael@0 | 56 | &(pop->popChoice.raVerified), |
michael@0 | 57 | CRMFRAVerifiedTemplate); |
michael@0 | 58 | return SECSuccess; |
michael@0 | 59 | loser: |
michael@0 | 60 | PORT_ArenaRelease(poolp, mark); |
michael@0 | 61 | return SECFailure; |
michael@0 | 62 | } |
michael@0 | 63 | |
michael@0 | 64 | static SECOidTag |
michael@0 | 65 | crmf_get_key_sign_tag(SECKEYPublicKey *inPubKey) |
michael@0 | 66 | { |
michael@0 | 67 | /* maintain backward compatibility with older |
michael@0 | 68 | * implementations */ |
michael@0 | 69 | if (inPubKey->keyType == rsaKey) { |
michael@0 | 70 | return SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION; |
michael@0 | 71 | } |
michael@0 | 72 | return SEC_GetSignatureAlgorithmOidTag(inPubKey->keyType, SEC_OID_UNKNOWN); |
michael@0 | 73 | } |
michael@0 | 74 | |
michael@0 | 75 | static SECAlgorithmID* |
michael@0 | 76 | crmf_create_poposignkey_algid(PLArenaPool *poolp, |
michael@0 | 77 | SECKEYPublicKey *inPubKey) |
michael@0 | 78 | { |
michael@0 | 79 | SECAlgorithmID *algID; |
michael@0 | 80 | SECOidTag tag; |
michael@0 | 81 | SECStatus rv; |
michael@0 | 82 | void *mark; |
michael@0 | 83 | |
michael@0 | 84 | mark = PORT_ArenaMark(poolp); |
michael@0 | 85 | algID = PORT_ArenaZNew(poolp, SECAlgorithmID); |
michael@0 | 86 | if (algID == NULL) { |
michael@0 | 87 | goto loser; |
michael@0 | 88 | } |
michael@0 | 89 | tag = crmf_get_key_sign_tag(inPubKey); |
michael@0 | 90 | if (tag == SEC_OID_UNKNOWN) { |
michael@0 | 91 | goto loser; |
michael@0 | 92 | } |
michael@0 | 93 | rv = SECOID_SetAlgorithmID(poolp, algID, tag, NULL); |
michael@0 | 94 | if (rv != SECSuccess) { |
michael@0 | 95 | goto loser; |
michael@0 | 96 | } |
michael@0 | 97 | PORT_ArenaUnmark(poolp, mark); |
michael@0 | 98 | return algID; |
michael@0 | 99 | loser: |
michael@0 | 100 | PORT_ArenaRelease(poolp, mark); |
michael@0 | 101 | return NULL; |
michael@0 | 102 | } |
michael@0 | 103 | |
michael@0 | 104 | static CRMFPOPOSigningKeyInput* |
michael@0 | 105 | crmf_create_poposigningkeyinput(PLArenaPool *poolp, CERTCertificate *inCert, |
michael@0 | 106 | CRMFMACPasswordCallback fn, void *arg) |
michael@0 | 107 | { |
michael@0 | 108 | /* PSM isn't going to do this, so we'll fail here for now.*/ |
michael@0 | 109 | return NULL; |
michael@0 | 110 | } |
michael@0 | 111 | |
michael@0 | 112 | void |
michael@0 | 113 | crmf_generic_encoder_callback(void *arg, const char* buf, unsigned long len, |
michael@0 | 114 | int depth, SEC_ASN1EncodingPart data_kind) |
michael@0 | 115 | { |
michael@0 | 116 | struct crmfEncoderArg *encoderArg = (struct crmfEncoderArg*)arg; |
michael@0 | 117 | unsigned char *cursor; |
michael@0 | 118 | |
michael@0 | 119 | if (encoderArg->buffer->len + len > encoderArg->allocatedLen) { |
michael@0 | 120 | int newSize = encoderArg->buffer->len+CRMF_DEFAULT_ALLOC_SIZE; |
michael@0 | 121 | void *dummy = PORT_Realloc(encoderArg->buffer->data, newSize); |
michael@0 | 122 | if (dummy == NULL) { |
michael@0 | 123 | /* I really want to return an error code here */ |
michael@0 | 124 | PORT_Assert(0); |
michael@0 | 125 | return; |
michael@0 | 126 | } |
michael@0 | 127 | encoderArg->buffer->data = dummy; |
michael@0 | 128 | encoderArg->allocatedLen = newSize; |
michael@0 | 129 | } |
michael@0 | 130 | cursor = &(encoderArg->buffer->data[encoderArg->buffer->len]); |
michael@0 | 131 | PORT_Memcpy (cursor, buf, len); |
michael@0 | 132 | encoderArg->buffer->len += len; |
michael@0 | 133 | } |
michael@0 | 134 | |
michael@0 | 135 | static SECStatus |
michael@0 | 136 | crmf_encode_certreq(CRMFCertRequest *inCertReq, SECItem *derDest) |
michael@0 | 137 | { |
michael@0 | 138 | struct crmfEncoderArg encoderArg; |
michael@0 | 139 | SECStatus rv; |
michael@0 | 140 | |
michael@0 | 141 | rv = crmf_init_encoder_callback_arg (&encoderArg, derDest); |
michael@0 | 142 | if (rv != SECSuccess) { |
michael@0 | 143 | return SECFailure; |
michael@0 | 144 | } |
michael@0 | 145 | return SEC_ASN1Encode(inCertReq, CRMFCertRequestTemplate, |
michael@0 | 146 | crmf_generic_encoder_callback, &encoderArg); |
michael@0 | 147 | } |
michael@0 | 148 | |
michael@0 | 149 | static SECStatus |
michael@0 | 150 | crmf_sign_certreq(PLArenaPool *poolp, |
michael@0 | 151 | CRMFPOPOSigningKey *crmfSignKey, |
michael@0 | 152 | CRMFCertRequest *certReq, |
michael@0 | 153 | SECKEYPrivateKey *inKey, |
michael@0 | 154 | SECAlgorithmID *inAlgId) |
michael@0 | 155 | { |
michael@0 | 156 | SECItem derCertReq = { siBuffer, NULL, 0 }; |
michael@0 | 157 | SECItem certReqSig = { siBuffer, NULL, 0 }; |
michael@0 | 158 | SECStatus rv = SECSuccess; |
michael@0 | 159 | |
michael@0 | 160 | rv = crmf_encode_certreq(certReq, &derCertReq); |
michael@0 | 161 | if (rv != SECSuccess) { |
michael@0 | 162 | goto loser; |
michael@0 | 163 | } |
michael@0 | 164 | rv = SEC_SignData(&certReqSig, derCertReq.data, derCertReq.len, |
michael@0 | 165 | inKey,SECOID_GetAlgorithmTag(inAlgId)); |
michael@0 | 166 | if (rv != SECSuccess) { |
michael@0 | 167 | goto loser; |
michael@0 | 168 | } |
michael@0 | 169 | |
michael@0 | 170 | /* Now make it a part of the POPOSigningKey */ |
michael@0 | 171 | rv = SECITEM_CopyItem(poolp, &(crmfSignKey->signature), &certReqSig); |
michael@0 | 172 | /* Convert this length to number of bits */ |
michael@0 | 173 | crmfSignKey->signature.len <<= 3; |
michael@0 | 174 | |
michael@0 | 175 | loser: |
michael@0 | 176 | if (derCertReq.data != NULL) { |
michael@0 | 177 | PORT_Free(derCertReq.data); |
michael@0 | 178 | } |
michael@0 | 179 | if (certReqSig.data != NULL) { |
michael@0 | 180 | PORT_Free(certReqSig.data); |
michael@0 | 181 | } |
michael@0 | 182 | return rv; |
michael@0 | 183 | } |
michael@0 | 184 | |
michael@0 | 185 | static SECStatus |
michael@0 | 186 | crmf_create_poposignkey(PLArenaPool *poolp, |
michael@0 | 187 | CRMFCertReqMsg *inCertReqMsg, |
michael@0 | 188 | CRMFPOPOSigningKeyInput *signKeyInput, |
michael@0 | 189 | SECKEYPrivateKey *inPrivKey, |
michael@0 | 190 | SECAlgorithmID *inAlgID, |
michael@0 | 191 | CRMFPOPOSigningKey *signKey) |
michael@0 | 192 | { |
michael@0 | 193 | CRMFCertRequest *certReq; |
michael@0 | 194 | void *mark; |
michael@0 | 195 | PRBool useSignKeyInput; |
michael@0 | 196 | SECStatus rv; |
michael@0 | 197 | |
michael@0 | 198 | PORT_Assert(inCertReqMsg != NULL && inCertReqMsg->certReq != NULL); |
michael@0 | 199 | mark = PORT_ArenaMark(poolp); |
michael@0 | 200 | if (signKey == NULL) { |
michael@0 | 201 | goto loser; |
michael@0 | 202 | } |
michael@0 | 203 | certReq = inCertReqMsg->certReq; |
michael@0 | 204 | useSignKeyInput = !(CRMF_DoesRequestHaveField(certReq,crmfSubject) && |
michael@0 | 205 | CRMF_DoesRequestHaveField(certReq,crmfPublicKey)); |
michael@0 | 206 | |
michael@0 | 207 | if (useSignKeyInput) { |
michael@0 | 208 | goto loser; |
michael@0 | 209 | } else { |
michael@0 | 210 | rv = crmf_sign_certreq(poolp, signKey, certReq,inPrivKey, inAlgID); |
michael@0 | 211 | if (rv != SECSuccess) { |
michael@0 | 212 | goto loser; |
michael@0 | 213 | } |
michael@0 | 214 | } |
michael@0 | 215 | PORT_ArenaUnmark(poolp,mark); |
michael@0 | 216 | return SECSuccess; |
michael@0 | 217 | loser: |
michael@0 | 218 | PORT_ArenaRelease(poolp,mark); |
michael@0 | 219 | return SECFailure; |
michael@0 | 220 | } |
michael@0 | 221 | |
michael@0 | 222 | SECStatus |
michael@0 | 223 | CRMF_CertReqMsgSetSignaturePOP(CRMFCertReqMsg *inCertReqMsg, |
michael@0 | 224 | SECKEYPrivateKey *inPrivKey, |
michael@0 | 225 | SECKEYPublicKey *inPubKey, |
michael@0 | 226 | CERTCertificate *inCertForInput, |
michael@0 | 227 | CRMFMACPasswordCallback fn, |
michael@0 | 228 | void *arg) |
michael@0 | 229 | { |
michael@0 | 230 | SECAlgorithmID *algID; |
michael@0 | 231 | PLArenaPool *poolp; |
michael@0 | 232 | SECItem derTemp = {siBuffer, NULL, 0}; |
michael@0 | 233 | void *mark; |
michael@0 | 234 | SECStatus rv; |
michael@0 | 235 | CRMFPOPOSigningKeyInput *signKeyInput = NULL; |
michael@0 | 236 | CRMFCertRequest *certReq; |
michael@0 | 237 | CRMFProofOfPossession *pop; |
michael@0 | 238 | struct crmfEncoderArg encoderArg; |
michael@0 | 239 | |
michael@0 | 240 | PORT_Assert(inCertReqMsg != NULL && inCertReqMsg->certReq != NULL && |
michael@0 | 241 | inCertReqMsg->pop == NULL); |
michael@0 | 242 | certReq = inCertReqMsg->certReq; |
michael@0 | 243 | if (CRMF_CertReqMsgGetPOPType(inCertReqMsg) != crmfNoPOPChoice || |
michael@0 | 244 | !CRMF_DoesRequestHaveField(certReq, crmfPublicKey)) { |
michael@0 | 245 | return SECFailure; |
michael@0 | 246 | } |
michael@0 | 247 | poolp = inCertReqMsg->poolp; |
michael@0 | 248 | mark = PORT_ArenaMark(poolp); |
michael@0 | 249 | algID = crmf_create_poposignkey_algid(poolp, inPubKey); |
michael@0 | 250 | |
michael@0 | 251 | if(!CRMF_DoesRequestHaveField(certReq,crmfSubject)) { |
michael@0 | 252 | signKeyInput = crmf_create_poposigningkeyinput(poolp, inCertForInput, |
michael@0 | 253 | fn, arg); |
michael@0 | 254 | if (signKeyInput == NULL) { |
michael@0 | 255 | goto loser; |
michael@0 | 256 | } |
michael@0 | 257 | } |
michael@0 | 258 | |
michael@0 | 259 | pop = PORT_ArenaZNew(poolp, CRMFProofOfPossession); |
michael@0 | 260 | if (pop == NULL) { |
michael@0 | 261 | goto loser; |
michael@0 | 262 | } |
michael@0 | 263 | |
michael@0 | 264 | rv = crmf_create_poposignkey(poolp, inCertReqMsg, |
michael@0 | 265 | signKeyInput, inPrivKey, algID, |
michael@0 | 266 | &(pop->popChoice.signature)); |
michael@0 | 267 | if (rv != SECSuccess) { |
michael@0 | 268 | goto loser; |
michael@0 | 269 | } |
michael@0 | 270 | |
michael@0 | 271 | pop->popUsed = crmfSignature; |
michael@0 | 272 | pop->popChoice.signature.algorithmIdentifier = algID; |
michael@0 | 273 | inCertReqMsg->pop = pop; |
michael@0 | 274 | |
michael@0 | 275 | rv = crmf_init_encoder_callback_arg (&encoderArg, &derTemp); |
michael@0 | 276 | if (rv != SECSuccess) { |
michael@0 | 277 | goto loser; |
michael@0 | 278 | } |
michael@0 | 279 | rv = SEC_ASN1Encode(&pop->popChoice.signature, |
michael@0 | 280 | CRMFPOPOSigningKeyTemplate, |
michael@0 | 281 | crmf_generic_encoder_callback, &encoderArg); |
michael@0 | 282 | if (rv != SECSuccess) { |
michael@0 | 283 | goto loser; |
michael@0 | 284 | } |
michael@0 | 285 | rv = SECITEM_CopyItem(poolp, &(inCertReqMsg->derPOP), &derTemp); |
michael@0 | 286 | if (rv != SECSuccess) { |
michael@0 | 287 | goto loser; |
michael@0 | 288 | } |
michael@0 | 289 | PORT_Free (derTemp.data); |
michael@0 | 290 | PORT_ArenaUnmark(poolp,mark); |
michael@0 | 291 | return SECSuccess; |
michael@0 | 292 | |
michael@0 | 293 | loser: |
michael@0 | 294 | PORT_ArenaRelease(poolp,mark); |
michael@0 | 295 | if (derTemp.data != NULL) { |
michael@0 | 296 | PORT_Free(derTemp.data); |
michael@0 | 297 | } |
michael@0 | 298 | return SECFailure; |
michael@0 | 299 | } |
michael@0 | 300 | |
michael@0 | 301 | static const SEC_ASN1Template* |
michael@0 | 302 | crmf_get_popoprivkey_subtemplate(CRMFPOPOPrivKey *inPrivKey) |
michael@0 | 303 | { |
michael@0 | 304 | const SEC_ASN1Template *retTemplate = NULL; |
michael@0 | 305 | |
michael@0 | 306 | switch (inPrivKey->messageChoice) { |
michael@0 | 307 | case crmfThisMessage: |
michael@0 | 308 | retTemplate = CRMFThisMessageTemplate; |
michael@0 | 309 | break; |
michael@0 | 310 | case crmfSubsequentMessage: |
michael@0 | 311 | retTemplate = CRMFSubsequentMessageTemplate; |
michael@0 | 312 | break; |
michael@0 | 313 | case crmfDHMAC: |
michael@0 | 314 | retTemplate = CRMFDHMACTemplate; |
michael@0 | 315 | break; |
michael@0 | 316 | default: |
michael@0 | 317 | retTemplate = NULL; |
michael@0 | 318 | } |
michael@0 | 319 | return retTemplate; |
michael@0 | 320 | } |
michael@0 | 321 | |
michael@0 | 322 | static SECStatus |
michael@0 | 323 | crmf_encode_popoprivkey(PLArenaPool *poolp, |
michael@0 | 324 | CRMFCertReqMsg *inCertReqMsg, |
michael@0 | 325 | CRMFPOPOPrivKey *popoPrivKey, |
michael@0 | 326 | const SEC_ASN1Template *privKeyTemplate) |
michael@0 | 327 | { |
michael@0 | 328 | struct crmfEncoderArg encoderArg; |
michael@0 | 329 | SECItem derTemp = { siBuffer, NULL, 0 }; |
michael@0 | 330 | SECStatus rv; |
michael@0 | 331 | void *mark; |
michael@0 | 332 | const SEC_ASN1Template *subDerTemplate; |
michael@0 | 333 | |
michael@0 | 334 | mark = PORT_ArenaMark(poolp); |
michael@0 | 335 | rv = crmf_init_encoder_callback_arg(&encoderArg, &derTemp); |
michael@0 | 336 | if (rv != SECSuccess) { |
michael@0 | 337 | goto loser; |
michael@0 | 338 | } |
michael@0 | 339 | subDerTemplate = crmf_get_popoprivkey_subtemplate(popoPrivKey); |
michael@0 | 340 | /* We've got a union, so a pointer to one item is a pointer to |
michael@0 | 341 | * all the items in the union. |
michael@0 | 342 | */ |
michael@0 | 343 | rv = SEC_ASN1Encode(&popoPrivKey->message.thisMessage, |
michael@0 | 344 | subDerTemplate, |
michael@0 | 345 | crmf_generic_encoder_callback, &encoderArg); |
michael@0 | 346 | if (rv != SECSuccess) { |
michael@0 | 347 | goto loser; |
michael@0 | 348 | } |
michael@0 | 349 | if (encoderArg.allocatedLen > derTemp.len+2) { |
michael@0 | 350 | void *dummy = PORT_Realloc(derTemp.data, derTemp.len+2); |
michael@0 | 351 | if (dummy == NULL) { |
michael@0 | 352 | goto loser; |
michael@0 | 353 | } |
michael@0 | 354 | derTemp.data = dummy; |
michael@0 | 355 | } |
michael@0 | 356 | PORT_Memmove(&derTemp.data[2], &derTemp.data[0], derTemp.len); |
michael@0 | 357 | /* I couldn't figure out how to get the ASN1 encoder to implicitly |
michael@0 | 358 | * tag an implicitly tagged der blob. So I'm putting in the outter- |
michael@0 | 359 | * most tag myself. -javi |
michael@0 | 360 | */ |
michael@0 | 361 | derTemp.data[0] = (unsigned char)privKeyTemplate->kind; |
michael@0 | 362 | derTemp.data[1] = (unsigned char)derTemp.len; |
michael@0 | 363 | derTemp.len += 2; |
michael@0 | 364 | rv = SECITEM_CopyItem(poolp, &inCertReqMsg->derPOP, &derTemp); |
michael@0 | 365 | if (rv != SECSuccess) { |
michael@0 | 366 | goto loser; |
michael@0 | 367 | } |
michael@0 | 368 | PORT_Free(derTemp.data); |
michael@0 | 369 | PORT_ArenaUnmark(poolp, mark); |
michael@0 | 370 | return SECSuccess; |
michael@0 | 371 | loser: |
michael@0 | 372 | PORT_ArenaRelease(poolp, mark); |
michael@0 | 373 | if (derTemp.data) { |
michael@0 | 374 | PORT_Free(derTemp.data); |
michael@0 | 375 | } |
michael@0 | 376 | return SECFailure; |
michael@0 | 377 | } |
michael@0 | 378 | |
michael@0 | 379 | static const SEC_ASN1Template* |
michael@0 | 380 | crmf_get_template_for_privkey(CRMFPOPChoice inChoice) |
michael@0 | 381 | { |
michael@0 | 382 | switch (inChoice) { |
michael@0 | 383 | case crmfKeyAgreement: |
michael@0 | 384 | return CRMFPOPOKeyAgreementTemplate; |
michael@0 | 385 | case crmfKeyEncipherment: |
michael@0 | 386 | return CRMFPOPOKeyEnciphermentTemplate; |
michael@0 | 387 | default: |
michael@0 | 388 | break; |
michael@0 | 389 | } |
michael@0 | 390 | return NULL; |
michael@0 | 391 | } |
michael@0 | 392 | |
michael@0 | 393 | static SECStatus |
michael@0 | 394 | crmf_add_privkey_thismessage(CRMFCertReqMsg *inCertReqMsg, SECItem *encPrivKey, |
michael@0 | 395 | CRMFPOPChoice inChoice) |
michael@0 | 396 | { |
michael@0 | 397 | PLArenaPool *poolp; |
michael@0 | 398 | void *mark; |
michael@0 | 399 | CRMFPOPOPrivKey *popoPrivKey; |
michael@0 | 400 | CRMFProofOfPossession *pop; |
michael@0 | 401 | SECStatus rv; |
michael@0 | 402 | |
michael@0 | 403 | PORT_Assert(inCertReqMsg != NULL && encPrivKey != NULL); |
michael@0 | 404 | poolp = inCertReqMsg->poolp; |
michael@0 | 405 | mark = PORT_ArenaMark(poolp); |
michael@0 | 406 | pop = PORT_ArenaZNew(poolp, CRMFProofOfPossession); |
michael@0 | 407 | if (pop == NULL) { |
michael@0 | 408 | goto loser; |
michael@0 | 409 | } |
michael@0 | 410 | pop->popUsed = inChoice; |
michael@0 | 411 | /* popChoice is a union, so getting a pointer to one |
michael@0 | 412 | * field gives me a pointer to the other fields as |
michael@0 | 413 | * well. This in essence points to both |
michael@0 | 414 | * pop->popChoice.keyEncipherment and |
michael@0 | 415 | * pop->popChoice.keyAgreement |
michael@0 | 416 | */ |
michael@0 | 417 | popoPrivKey = &pop->popChoice.keyEncipherment; |
michael@0 | 418 | |
michael@0 | 419 | rv = SECITEM_CopyItem(poolp, &(popoPrivKey->message.thisMessage), |
michael@0 | 420 | encPrivKey); |
michael@0 | 421 | if (rv != SECSuccess) { |
michael@0 | 422 | goto loser; |
michael@0 | 423 | } |
michael@0 | 424 | popoPrivKey->message.thisMessage.len <<= 3; |
michael@0 | 425 | popoPrivKey->messageChoice = crmfThisMessage; |
michael@0 | 426 | inCertReqMsg->pop = pop; |
michael@0 | 427 | rv = crmf_encode_popoprivkey(poolp, inCertReqMsg, popoPrivKey, |
michael@0 | 428 | crmf_get_template_for_privkey(inChoice)); |
michael@0 | 429 | if (rv != SECSuccess) { |
michael@0 | 430 | goto loser; |
michael@0 | 431 | } |
michael@0 | 432 | PORT_ArenaUnmark(poolp, mark); |
michael@0 | 433 | return SECSuccess; |
michael@0 | 434 | |
michael@0 | 435 | loser: |
michael@0 | 436 | PORT_ArenaRelease(poolp, mark); |
michael@0 | 437 | return SECFailure; |
michael@0 | 438 | } |
michael@0 | 439 | |
michael@0 | 440 | static SECStatus |
michael@0 | 441 | crmf_add_privkey_dhmac(CRMFCertReqMsg *inCertReqMsg, SECItem *dhmac, |
michael@0 | 442 | CRMFPOPChoice inChoice) |
michael@0 | 443 | { |
michael@0 | 444 | PLArenaPool *poolp; |
michael@0 | 445 | void *mark; |
michael@0 | 446 | CRMFPOPOPrivKey *popoPrivKey; |
michael@0 | 447 | CRMFProofOfPossession *pop; |
michael@0 | 448 | SECStatus rv; |
michael@0 | 449 | |
michael@0 | 450 | PORT_Assert(inCertReqMsg != NULL && dhmac != NULL); |
michael@0 | 451 | poolp = inCertReqMsg->poolp; |
michael@0 | 452 | mark = PORT_ArenaMark(poolp); |
michael@0 | 453 | pop = PORT_ArenaZNew(poolp, CRMFProofOfPossession); |
michael@0 | 454 | if (pop == NULL) { |
michael@0 | 455 | goto loser; |
michael@0 | 456 | } |
michael@0 | 457 | pop->popUsed = inChoice; |
michael@0 | 458 | popoPrivKey = &pop->popChoice.keyAgreement; |
michael@0 | 459 | |
michael@0 | 460 | rv = SECITEM_CopyItem(poolp, &(popoPrivKey->message.dhMAC), |
michael@0 | 461 | dhmac); |
michael@0 | 462 | if (rv != SECSuccess) { |
michael@0 | 463 | goto loser; |
michael@0 | 464 | } |
michael@0 | 465 | popoPrivKey->message.dhMAC.len <<= 3; |
michael@0 | 466 | popoPrivKey->messageChoice = crmfDHMAC; |
michael@0 | 467 | inCertReqMsg->pop = pop; |
michael@0 | 468 | rv = crmf_encode_popoprivkey(poolp, inCertReqMsg, popoPrivKey, |
michael@0 | 469 | crmf_get_template_for_privkey(inChoice)); |
michael@0 | 470 | if (rv != SECSuccess) { |
michael@0 | 471 | goto loser; |
michael@0 | 472 | } |
michael@0 | 473 | PORT_ArenaUnmark(poolp, mark); |
michael@0 | 474 | return SECSuccess; |
michael@0 | 475 | |
michael@0 | 476 | loser: |
michael@0 | 477 | PORT_ArenaRelease(poolp, mark); |
michael@0 | 478 | return SECFailure; |
michael@0 | 479 | } |
michael@0 | 480 | |
michael@0 | 481 | static SECStatus |
michael@0 | 482 | crmf_add_privkey_subseqmessage(CRMFCertReqMsg *inCertReqMsg, |
michael@0 | 483 | CRMFSubseqMessOptions subsequentMessage, |
michael@0 | 484 | CRMFPOPChoice inChoice) |
michael@0 | 485 | { |
michael@0 | 486 | void *mark; |
michael@0 | 487 | PLArenaPool *poolp; |
michael@0 | 488 | CRMFProofOfPossession *pop; |
michael@0 | 489 | CRMFPOPOPrivKey *popoPrivKey; |
michael@0 | 490 | SECStatus rv; |
michael@0 | 491 | const SEC_ASN1Template *privKeyTemplate; |
michael@0 | 492 | |
michael@0 | 493 | if (subsequentMessage == crmfNoSubseqMess) { |
michael@0 | 494 | return SECFailure; |
michael@0 | 495 | } |
michael@0 | 496 | poolp = inCertReqMsg->poolp; |
michael@0 | 497 | mark = PORT_ArenaMark(poolp); |
michael@0 | 498 | pop = PORT_ArenaZNew(poolp, CRMFProofOfPossession); |
michael@0 | 499 | if (pop == NULL) { |
michael@0 | 500 | goto loser; |
michael@0 | 501 | } |
michael@0 | 502 | |
michael@0 | 503 | pop->popUsed = inChoice; |
michael@0 | 504 | /* |
michael@0 | 505 | * We have a union, so a pointer to one member of the union |
michael@0 | 506 | * is also a member to another member of that same union. |
michael@0 | 507 | */ |
michael@0 | 508 | popoPrivKey = &pop->popChoice.keyEncipherment; |
michael@0 | 509 | |
michael@0 | 510 | switch (subsequentMessage) { |
michael@0 | 511 | case crmfEncrCert: |
michael@0 | 512 | rv = crmf_encode_integer(poolp, |
michael@0 | 513 | &(popoPrivKey->message.subsequentMessage), |
michael@0 | 514 | 0); |
michael@0 | 515 | break; |
michael@0 | 516 | case crmfChallengeResp: |
michael@0 | 517 | rv = crmf_encode_integer(poolp, |
michael@0 | 518 | &(popoPrivKey->message.subsequentMessage), |
michael@0 | 519 | 1); |
michael@0 | 520 | break; |
michael@0 | 521 | default: |
michael@0 | 522 | goto loser; |
michael@0 | 523 | } |
michael@0 | 524 | if (rv != SECSuccess) { |
michael@0 | 525 | goto loser; |
michael@0 | 526 | } |
michael@0 | 527 | popoPrivKey->messageChoice = crmfSubsequentMessage; |
michael@0 | 528 | privKeyTemplate = crmf_get_template_for_privkey(inChoice); |
michael@0 | 529 | inCertReqMsg->pop = pop; |
michael@0 | 530 | rv = crmf_encode_popoprivkey(poolp, inCertReqMsg, popoPrivKey, |
michael@0 | 531 | privKeyTemplate); |
michael@0 | 532 | |
michael@0 | 533 | if (rv != SECSuccess) { |
michael@0 | 534 | goto loser; |
michael@0 | 535 | } |
michael@0 | 536 | PORT_ArenaUnmark(poolp, mark); |
michael@0 | 537 | return SECSuccess; |
michael@0 | 538 | loser: |
michael@0 | 539 | PORT_ArenaRelease(poolp, mark); |
michael@0 | 540 | return SECFailure; |
michael@0 | 541 | } |
michael@0 | 542 | |
michael@0 | 543 | SECStatus |
michael@0 | 544 | CRMF_CertReqMsgSetKeyEnciphermentPOP(CRMFCertReqMsg *inCertReqMsg, |
michael@0 | 545 | CRMFPOPOPrivKeyChoice inKeyChoice, |
michael@0 | 546 | CRMFSubseqMessOptions subseqMess, |
michael@0 | 547 | SECItem *encPrivKey) |
michael@0 | 548 | { |
michael@0 | 549 | SECStatus rv; |
michael@0 | 550 | |
michael@0 | 551 | PORT_Assert(inCertReqMsg != NULL && inCertReqMsg->pop == NULL); |
michael@0 | 552 | if (CRMF_CertReqMsgGetPOPType(inCertReqMsg) != crmfNoPOPChoice) { |
michael@0 | 553 | return SECFailure; |
michael@0 | 554 | } |
michael@0 | 555 | switch (inKeyChoice) { |
michael@0 | 556 | case crmfThisMessage: |
michael@0 | 557 | rv = crmf_add_privkey_thismessage(inCertReqMsg, encPrivKey, |
michael@0 | 558 | crmfKeyEncipherment); |
michael@0 | 559 | break; |
michael@0 | 560 | case crmfSubsequentMessage: |
michael@0 | 561 | rv = crmf_add_privkey_subseqmessage(inCertReqMsg, subseqMess, |
michael@0 | 562 | crmfKeyEncipherment); |
michael@0 | 563 | break; |
michael@0 | 564 | case crmfDHMAC: |
michael@0 | 565 | default: |
michael@0 | 566 | rv = SECFailure; |
michael@0 | 567 | } |
michael@0 | 568 | return rv; |
michael@0 | 569 | } |
michael@0 | 570 | |
michael@0 | 571 | SECStatus |
michael@0 | 572 | CRMF_CertReqMsgSetKeyAgreementPOP (CRMFCertReqMsg *inCertReqMsg, |
michael@0 | 573 | CRMFPOPOPrivKeyChoice inKeyChoice, |
michael@0 | 574 | CRMFSubseqMessOptions subseqMess, |
michael@0 | 575 | SECItem *encPrivKey) |
michael@0 | 576 | { |
michael@0 | 577 | SECStatus rv; |
michael@0 | 578 | |
michael@0 | 579 | PORT_Assert(inCertReqMsg != NULL && inCertReqMsg->pop == NULL); |
michael@0 | 580 | switch (inKeyChoice) { |
michael@0 | 581 | case crmfThisMessage: |
michael@0 | 582 | rv = crmf_add_privkey_thismessage(inCertReqMsg, encPrivKey, |
michael@0 | 583 | crmfKeyAgreement); |
michael@0 | 584 | break; |
michael@0 | 585 | case crmfSubsequentMessage: |
michael@0 | 586 | rv = crmf_add_privkey_subseqmessage(inCertReqMsg, subseqMess, |
michael@0 | 587 | crmfKeyAgreement); |
michael@0 | 588 | break; |
michael@0 | 589 | case crmfDHMAC: |
michael@0 | 590 | /* In this case encPrivKey should be the calculated dhMac |
michael@0 | 591 | * as specified in RFC 2511 */ |
michael@0 | 592 | rv = crmf_add_privkey_dhmac(inCertReqMsg, encPrivKey, |
michael@0 | 593 | crmfKeyAgreement); |
michael@0 | 594 | break; |
michael@0 | 595 | default: |
michael@0 | 596 | rv = SECFailure; |
michael@0 | 597 | } |
michael@0 | 598 | return rv; |
michael@0 | 599 | } |
michael@0 | 600 |