Wed, 31 Dec 2014 06:09:35 +0100
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 | #include "crmf.h" |
michael@0 | 7 | #include "crmfi.h" |
michael@0 | 8 | #include "pk11func.h" |
michael@0 | 9 | #include "keyhi.h" |
michael@0 | 10 | #include "secoid.h" |
michael@0 | 11 | |
michael@0 | 12 | static SECStatus |
michael@0 | 13 | crmf_modify_control_array (CRMFCertRequest *inCertReq, int count) |
michael@0 | 14 | { |
michael@0 | 15 | if (count > 0) { |
michael@0 | 16 | void *dummy = PORT_Realloc(inCertReq->controls, |
michael@0 | 17 | sizeof(CRMFControl*)*(count+2)); |
michael@0 | 18 | if (dummy == NULL) { |
michael@0 | 19 | return SECFailure; |
michael@0 | 20 | } |
michael@0 | 21 | inCertReq->controls = dummy; |
michael@0 | 22 | } else { |
michael@0 | 23 | inCertReq->controls = PORT_ZNewArray(CRMFControl*, 2); |
michael@0 | 24 | } |
michael@0 | 25 | return (inCertReq->controls == NULL) ? SECFailure : SECSuccess ; |
michael@0 | 26 | } |
michael@0 | 27 | |
michael@0 | 28 | static SECStatus |
michael@0 | 29 | crmf_add_new_control(CRMFCertRequest *inCertReq,SECOidTag inTag, |
michael@0 | 30 | CRMFControl **destControl) |
michael@0 | 31 | { |
michael@0 | 32 | SECOidData *oidData; |
michael@0 | 33 | SECStatus rv; |
michael@0 | 34 | PLArenaPool *poolp; |
michael@0 | 35 | int numControls = 0; |
michael@0 | 36 | CRMFControl *newControl; |
michael@0 | 37 | CRMFControl **controls; |
michael@0 | 38 | void *mark; |
michael@0 | 39 | |
michael@0 | 40 | poolp = inCertReq->poolp; |
michael@0 | 41 | if (poolp == NULL) { |
michael@0 | 42 | return SECFailure; |
michael@0 | 43 | } |
michael@0 | 44 | mark = PORT_ArenaMark(poolp); |
michael@0 | 45 | if (inCertReq->controls != NULL) { |
michael@0 | 46 | while (inCertReq->controls[numControls] != NULL) |
michael@0 | 47 | numControls++; |
michael@0 | 48 | } |
michael@0 | 49 | rv = crmf_modify_control_array(inCertReq, numControls); |
michael@0 | 50 | if (rv != SECSuccess) { |
michael@0 | 51 | goto loser; |
michael@0 | 52 | } |
michael@0 | 53 | controls = inCertReq->controls; |
michael@0 | 54 | oidData = SECOID_FindOIDByTag(inTag); |
michael@0 | 55 | newControl = *destControl = PORT_ArenaZNew(poolp,CRMFControl); |
michael@0 | 56 | if (newControl == NULL) { |
michael@0 | 57 | goto loser; |
michael@0 | 58 | } |
michael@0 | 59 | rv = SECITEM_CopyItem(poolp, &newControl->derTag, &oidData->oid); |
michael@0 | 60 | if (rv != SECSuccess) { |
michael@0 | 61 | goto loser; |
michael@0 | 62 | } |
michael@0 | 63 | newControl->tag = inTag; |
michael@0 | 64 | controls[numControls] = newControl; |
michael@0 | 65 | controls[numControls+1] = NULL; |
michael@0 | 66 | PORT_ArenaUnmark(poolp, mark); |
michael@0 | 67 | return SECSuccess; |
michael@0 | 68 | |
michael@0 | 69 | loser: |
michael@0 | 70 | PORT_ArenaRelease(poolp, mark); |
michael@0 | 71 | *destControl = NULL; |
michael@0 | 72 | return SECFailure; |
michael@0 | 73 | |
michael@0 | 74 | } |
michael@0 | 75 | |
michael@0 | 76 | static SECStatus |
michael@0 | 77 | crmf_add_secitem_control(CRMFCertRequest *inCertReq, SECItem *value, |
michael@0 | 78 | SECOidTag inTag) |
michael@0 | 79 | { |
michael@0 | 80 | SECStatus rv; |
michael@0 | 81 | CRMFControl *newControl; |
michael@0 | 82 | void *mark; |
michael@0 | 83 | |
michael@0 | 84 | rv = crmf_add_new_control(inCertReq, inTag, &newControl); |
michael@0 | 85 | if (rv != SECSuccess) { |
michael@0 | 86 | return rv; |
michael@0 | 87 | } |
michael@0 | 88 | mark = PORT_ArenaMark(inCertReq->poolp); |
michael@0 | 89 | rv = SECITEM_CopyItem(inCertReq->poolp, &newControl->derValue, value); |
michael@0 | 90 | if (rv != SECSuccess) { |
michael@0 | 91 | PORT_ArenaRelease(inCertReq->poolp, mark); |
michael@0 | 92 | return rv; |
michael@0 | 93 | } |
michael@0 | 94 | PORT_ArenaUnmark(inCertReq->poolp, mark); |
michael@0 | 95 | return SECSuccess; |
michael@0 | 96 | } |
michael@0 | 97 | |
michael@0 | 98 | SECStatus |
michael@0 | 99 | CRMF_CertRequestSetRegTokenControl(CRMFCertRequest *inCertReq, SECItem *value) |
michael@0 | 100 | { |
michael@0 | 101 | return crmf_add_secitem_control(inCertReq, value, |
michael@0 | 102 | SEC_OID_PKIX_REGCTRL_REGTOKEN); |
michael@0 | 103 | } |
michael@0 | 104 | |
michael@0 | 105 | SECStatus |
michael@0 | 106 | CRMF_CertRequestSetAuthenticatorControl (CRMFCertRequest *inCertReq, |
michael@0 | 107 | SECItem *value) |
michael@0 | 108 | { |
michael@0 | 109 | return crmf_add_secitem_control(inCertReq, value, |
michael@0 | 110 | SEC_OID_PKIX_REGCTRL_AUTHENTICATOR); |
michael@0 | 111 | } |
michael@0 | 112 | |
michael@0 | 113 | SECStatus |
michael@0 | 114 | crmf_destroy_encrypted_value(CRMFEncryptedValue *inEncrValue, PRBool freeit) |
michael@0 | 115 | { |
michael@0 | 116 | if (inEncrValue != NULL) { |
michael@0 | 117 | if (inEncrValue->intendedAlg) { |
michael@0 | 118 | SECOID_DestroyAlgorithmID(inEncrValue->intendedAlg, PR_TRUE); |
michael@0 | 119 | inEncrValue->intendedAlg = NULL; |
michael@0 | 120 | } |
michael@0 | 121 | if (inEncrValue->symmAlg) { |
michael@0 | 122 | SECOID_DestroyAlgorithmID(inEncrValue->symmAlg, PR_TRUE); |
michael@0 | 123 | inEncrValue->symmAlg = NULL; |
michael@0 | 124 | } |
michael@0 | 125 | if (inEncrValue->encSymmKey.data) { |
michael@0 | 126 | PORT_Free(inEncrValue->encSymmKey.data); |
michael@0 | 127 | inEncrValue->encSymmKey.data = NULL; |
michael@0 | 128 | } |
michael@0 | 129 | if (inEncrValue->keyAlg) { |
michael@0 | 130 | SECOID_DestroyAlgorithmID(inEncrValue->keyAlg, PR_TRUE); |
michael@0 | 131 | inEncrValue->keyAlg = NULL; |
michael@0 | 132 | } |
michael@0 | 133 | if (inEncrValue->valueHint.data) { |
michael@0 | 134 | PORT_Free(inEncrValue->valueHint.data); |
michael@0 | 135 | inEncrValue->valueHint.data = NULL; |
michael@0 | 136 | } |
michael@0 | 137 | if (inEncrValue->encValue.data) { |
michael@0 | 138 | PORT_Free(inEncrValue->encValue.data); |
michael@0 | 139 | inEncrValue->encValue.data = NULL; |
michael@0 | 140 | } |
michael@0 | 141 | if (freeit) { |
michael@0 | 142 | PORT_Free(inEncrValue); |
michael@0 | 143 | } |
michael@0 | 144 | } |
michael@0 | 145 | return SECSuccess; |
michael@0 | 146 | } |
michael@0 | 147 | |
michael@0 | 148 | SECStatus |
michael@0 | 149 | CRMF_DestroyEncryptedValue(CRMFEncryptedValue *inEncrValue) |
michael@0 | 150 | { |
michael@0 | 151 | return crmf_destroy_encrypted_value(inEncrValue, PR_TRUE); |
michael@0 | 152 | } |
michael@0 | 153 | |
michael@0 | 154 | SECStatus |
michael@0 | 155 | crmf_copy_encryptedvalue_secalg(PLArenaPool *poolp, |
michael@0 | 156 | SECAlgorithmID *srcAlgId, |
michael@0 | 157 | SECAlgorithmID **destAlgId) |
michael@0 | 158 | { |
michael@0 | 159 | SECAlgorithmID *newAlgId; |
michael@0 | 160 | SECStatus rv; |
michael@0 | 161 | |
michael@0 | 162 | newAlgId = (poolp != NULL) ? PORT_ArenaZNew(poolp, SECAlgorithmID) : |
michael@0 | 163 | PORT_ZNew(SECAlgorithmID); |
michael@0 | 164 | if (newAlgId == NULL) { |
michael@0 | 165 | return SECFailure; |
michael@0 | 166 | } |
michael@0 | 167 | |
michael@0 | 168 | rv = SECOID_CopyAlgorithmID(poolp, newAlgId, srcAlgId); |
michael@0 | 169 | if (rv != SECSuccess) { |
michael@0 | 170 | if (!poolp) { |
michael@0 | 171 | SECOID_DestroyAlgorithmID(newAlgId, PR_TRUE); |
michael@0 | 172 | } |
michael@0 | 173 | return rv; |
michael@0 | 174 | } |
michael@0 | 175 | *destAlgId = newAlgId; |
michael@0 | 176 | |
michael@0 | 177 | return rv; |
michael@0 | 178 | } |
michael@0 | 179 | |
michael@0 | 180 | SECStatus |
michael@0 | 181 | crmf_copy_encryptedvalue(PLArenaPool *poolp, |
michael@0 | 182 | CRMFEncryptedValue *srcValue, |
michael@0 | 183 | CRMFEncryptedValue *destValue) |
michael@0 | 184 | { |
michael@0 | 185 | SECStatus rv; |
michael@0 | 186 | |
michael@0 | 187 | if (srcValue->intendedAlg != NULL) { |
michael@0 | 188 | rv = crmf_copy_encryptedvalue_secalg(poolp, |
michael@0 | 189 | srcValue->intendedAlg, |
michael@0 | 190 | &destValue->intendedAlg); |
michael@0 | 191 | if (rv != SECSuccess) { |
michael@0 | 192 | goto loser; |
michael@0 | 193 | } |
michael@0 | 194 | } |
michael@0 | 195 | if (srcValue->symmAlg != NULL) { |
michael@0 | 196 | rv = crmf_copy_encryptedvalue_secalg(poolp, |
michael@0 | 197 | srcValue->symmAlg, |
michael@0 | 198 | &destValue->symmAlg); |
michael@0 | 199 | if (rv != SECSuccess) { |
michael@0 | 200 | goto loser; |
michael@0 | 201 | } |
michael@0 | 202 | } |
michael@0 | 203 | if (srcValue->encSymmKey.data != NULL) { |
michael@0 | 204 | rv = crmf_make_bitstring_copy(poolp, |
michael@0 | 205 | &destValue->encSymmKey, |
michael@0 | 206 | &srcValue->encSymmKey); |
michael@0 | 207 | if (rv != SECSuccess) { |
michael@0 | 208 | goto loser; |
michael@0 | 209 | } |
michael@0 | 210 | } |
michael@0 | 211 | if (srcValue->keyAlg != NULL) { |
michael@0 | 212 | rv = crmf_copy_encryptedvalue_secalg(poolp, |
michael@0 | 213 | srcValue->keyAlg, |
michael@0 | 214 | &destValue->keyAlg); |
michael@0 | 215 | if (rv != SECSuccess) { |
michael@0 | 216 | goto loser; |
michael@0 | 217 | } |
michael@0 | 218 | } |
michael@0 | 219 | if (srcValue->valueHint.data != NULL) { |
michael@0 | 220 | rv = SECITEM_CopyItem(poolp, |
michael@0 | 221 | &destValue->valueHint, |
michael@0 | 222 | &srcValue->valueHint); |
michael@0 | 223 | if (rv != SECSuccess) { |
michael@0 | 224 | goto loser; |
michael@0 | 225 | } |
michael@0 | 226 | } |
michael@0 | 227 | if (srcValue->encValue.data != NULL) { |
michael@0 | 228 | rv = crmf_make_bitstring_copy(poolp, |
michael@0 | 229 | &destValue->encValue, |
michael@0 | 230 | &srcValue->encValue); |
michael@0 | 231 | if (rv != SECSuccess) { |
michael@0 | 232 | goto loser; |
michael@0 | 233 | } |
michael@0 | 234 | } |
michael@0 | 235 | return SECSuccess; |
michael@0 | 236 | loser: |
michael@0 | 237 | if (poolp == NULL && destValue != NULL) { |
michael@0 | 238 | crmf_destroy_encrypted_value(destValue, PR_FALSE); |
michael@0 | 239 | } |
michael@0 | 240 | return SECFailure; |
michael@0 | 241 | } |
michael@0 | 242 | |
michael@0 | 243 | SECStatus |
michael@0 | 244 | crmf_copy_encryptedkey(PLArenaPool *poolp, |
michael@0 | 245 | CRMFEncryptedKey *srcEncrKey, |
michael@0 | 246 | CRMFEncryptedKey *destEncrKey) |
michael@0 | 247 | { |
michael@0 | 248 | SECStatus rv; |
michael@0 | 249 | void *mark = NULL; |
michael@0 | 250 | |
michael@0 | 251 | if (poolp != NULL) { |
michael@0 | 252 | mark = PORT_ArenaMark(poolp); |
michael@0 | 253 | } |
michael@0 | 254 | |
michael@0 | 255 | switch (srcEncrKey->encKeyChoice) { |
michael@0 | 256 | case crmfEncryptedValueChoice: |
michael@0 | 257 | rv = crmf_copy_encryptedvalue(poolp, |
michael@0 | 258 | &srcEncrKey->value.encryptedValue, |
michael@0 | 259 | &destEncrKey->value.encryptedValue); |
michael@0 | 260 | break; |
michael@0 | 261 | case crmfEnvelopedDataChoice: |
michael@0 | 262 | destEncrKey->value.envelopedData = |
michael@0 | 263 | SEC_PKCS7CopyContentInfo(srcEncrKey->value.envelopedData); |
michael@0 | 264 | rv = (destEncrKey->value.envelopedData != NULL) ? SECSuccess: |
michael@0 | 265 | SECFailure; |
michael@0 | 266 | break; |
michael@0 | 267 | default: |
michael@0 | 268 | rv = SECFailure; |
michael@0 | 269 | } |
michael@0 | 270 | if (rv != SECSuccess) { |
michael@0 | 271 | goto loser; |
michael@0 | 272 | } |
michael@0 | 273 | destEncrKey->encKeyChoice = srcEncrKey->encKeyChoice; |
michael@0 | 274 | if (mark) { |
michael@0 | 275 | PORT_ArenaUnmark(poolp, mark); |
michael@0 | 276 | } |
michael@0 | 277 | return SECSuccess; |
michael@0 | 278 | |
michael@0 | 279 | loser: |
michael@0 | 280 | if (mark) { |
michael@0 | 281 | PORT_ArenaRelease(poolp, mark); |
michael@0 | 282 | } |
michael@0 | 283 | return SECFailure; |
michael@0 | 284 | } |
michael@0 | 285 | |
michael@0 | 286 | static CRMFPKIArchiveOptions* |
michael@0 | 287 | crmf_create_encr_pivkey_option(CRMFEncryptedKey *inEncryptedKey) |
michael@0 | 288 | { |
michael@0 | 289 | CRMFPKIArchiveOptions *newArchOpt; |
michael@0 | 290 | SECStatus rv; |
michael@0 | 291 | |
michael@0 | 292 | newArchOpt = PORT_ZNew(CRMFPKIArchiveOptions); |
michael@0 | 293 | if (newArchOpt == NULL) { |
michael@0 | 294 | goto loser; |
michael@0 | 295 | } |
michael@0 | 296 | |
michael@0 | 297 | rv = crmf_copy_encryptedkey(NULL, inEncryptedKey, |
michael@0 | 298 | &newArchOpt->option.encryptedKey); |
michael@0 | 299 | |
michael@0 | 300 | if (rv != SECSuccess) { |
michael@0 | 301 | goto loser; |
michael@0 | 302 | } |
michael@0 | 303 | newArchOpt->archOption = crmfEncryptedPrivateKey; |
michael@0 | 304 | return newArchOpt; |
michael@0 | 305 | loser: |
michael@0 | 306 | if (newArchOpt != NULL) { |
michael@0 | 307 | CRMF_DestroyPKIArchiveOptions(newArchOpt); |
michael@0 | 308 | } |
michael@0 | 309 | return NULL; |
michael@0 | 310 | } |
michael@0 | 311 | |
michael@0 | 312 | static CRMFPKIArchiveOptions* |
michael@0 | 313 | crmf_create_keygen_param_option(SECItem *inKeyGenParams) |
michael@0 | 314 | { |
michael@0 | 315 | CRMFPKIArchiveOptions *newArchOptions; |
michael@0 | 316 | SECStatus rv; |
michael@0 | 317 | |
michael@0 | 318 | newArchOptions = PORT_ZNew(CRMFPKIArchiveOptions); |
michael@0 | 319 | if (newArchOptions == NULL) { |
michael@0 | 320 | goto loser; |
michael@0 | 321 | } |
michael@0 | 322 | newArchOptions->archOption = crmfKeyGenParameters; |
michael@0 | 323 | rv = SECITEM_CopyItem(NULL, &newArchOptions->option.keyGenParameters, |
michael@0 | 324 | inKeyGenParams); |
michael@0 | 325 | if (rv != SECSuccess) { |
michael@0 | 326 | goto loser; |
michael@0 | 327 | } |
michael@0 | 328 | return newArchOptions; |
michael@0 | 329 | loser: |
michael@0 | 330 | if (newArchOptions != NULL) { |
michael@0 | 331 | CRMF_DestroyPKIArchiveOptions(newArchOptions); |
michael@0 | 332 | } |
michael@0 | 333 | return NULL; |
michael@0 | 334 | } |
michael@0 | 335 | |
michael@0 | 336 | static CRMFPKIArchiveOptions* |
michael@0 | 337 | crmf_create_arch_rem_gen_privkey(PRBool archiveRemGenPrivKey) |
michael@0 | 338 | { |
michael@0 | 339 | unsigned char value; |
michael@0 | 340 | SECItem *dummy; |
michael@0 | 341 | CRMFPKIArchiveOptions *newArchOptions; |
michael@0 | 342 | |
michael@0 | 343 | value = (archiveRemGenPrivKey) ? hexTrue : hexFalse; |
michael@0 | 344 | newArchOptions = PORT_ZNew(CRMFPKIArchiveOptions); |
michael@0 | 345 | if (newArchOptions == NULL) { |
michael@0 | 346 | goto loser; |
michael@0 | 347 | } |
michael@0 | 348 | dummy = SEC_ASN1EncodeItem(NULL, |
michael@0 | 349 | &newArchOptions->option.archiveRemGenPrivKey, |
michael@0 | 350 | &value, SEC_ASN1_GET(SEC_BooleanTemplate)); |
michael@0 | 351 | PORT_Assert (dummy == &newArchOptions->option.archiveRemGenPrivKey); |
michael@0 | 352 | if (dummy != &newArchOptions->option.archiveRemGenPrivKey) { |
michael@0 | 353 | SECITEM_FreeItem (dummy, PR_TRUE); |
michael@0 | 354 | goto loser; |
michael@0 | 355 | } |
michael@0 | 356 | newArchOptions->archOption = crmfArchiveRemGenPrivKey; |
michael@0 | 357 | return newArchOptions; |
michael@0 | 358 | loser: |
michael@0 | 359 | if (newArchOptions != NULL) { |
michael@0 | 360 | CRMF_DestroyPKIArchiveOptions(newArchOptions); |
michael@0 | 361 | } |
michael@0 | 362 | return NULL; |
michael@0 | 363 | } |
michael@0 | 364 | |
michael@0 | 365 | CRMFPKIArchiveOptions* |
michael@0 | 366 | CRMF_CreatePKIArchiveOptions(CRMFPKIArchiveOptionsType inType, void *data) |
michael@0 | 367 | { |
michael@0 | 368 | CRMFPKIArchiveOptions* retOptions; |
michael@0 | 369 | |
michael@0 | 370 | PORT_Assert(data != NULL); |
michael@0 | 371 | if (data == NULL) { |
michael@0 | 372 | return NULL; |
michael@0 | 373 | } |
michael@0 | 374 | switch(inType) { |
michael@0 | 375 | case crmfEncryptedPrivateKey: |
michael@0 | 376 | retOptions = crmf_create_encr_pivkey_option((CRMFEncryptedKey*)data); |
michael@0 | 377 | break; |
michael@0 | 378 | case crmfKeyGenParameters: |
michael@0 | 379 | retOptions = crmf_create_keygen_param_option((SECItem*)data); |
michael@0 | 380 | break; |
michael@0 | 381 | case crmfArchiveRemGenPrivKey: |
michael@0 | 382 | retOptions = crmf_create_arch_rem_gen_privkey(*(PRBool*)data); |
michael@0 | 383 | break; |
michael@0 | 384 | default: |
michael@0 | 385 | retOptions = NULL; |
michael@0 | 386 | } |
michael@0 | 387 | return retOptions; |
michael@0 | 388 | } |
michael@0 | 389 | |
michael@0 | 390 | static SECStatus |
michael@0 | 391 | crmf_destroy_encrypted_key(CRMFEncryptedKey *inEncrKey, PRBool freeit) |
michael@0 | 392 | { |
michael@0 | 393 | PORT_Assert(inEncrKey != NULL); |
michael@0 | 394 | if (inEncrKey != NULL) { |
michael@0 | 395 | switch (inEncrKey->encKeyChoice){ |
michael@0 | 396 | case crmfEncryptedValueChoice: |
michael@0 | 397 | crmf_destroy_encrypted_value(&inEncrKey->value.encryptedValue, |
michael@0 | 398 | PR_FALSE); |
michael@0 | 399 | break; |
michael@0 | 400 | case crmfEnvelopedDataChoice: |
michael@0 | 401 | SEC_PKCS7DestroyContentInfo(inEncrKey->value.envelopedData); |
michael@0 | 402 | break; |
michael@0 | 403 | default: |
michael@0 | 404 | break; |
michael@0 | 405 | } |
michael@0 | 406 | if (freeit) { |
michael@0 | 407 | PORT_Free(inEncrKey); |
michael@0 | 408 | } |
michael@0 | 409 | } |
michael@0 | 410 | return SECSuccess; |
michael@0 | 411 | } |
michael@0 | 412 | |
michael@0 | 413 | SECStatus |
michael@0 | 414 | crmf_destroy_pkiarchiveoptions(CRMFPKIArchiveOptions *inArchOptions, |
michael@0 | 415 | PRBool freeit) |
michael@0 | 416 | { |
michael@0 | 417 | PORT_Assert(inArchOptions != NULL); |
michael@0 | 418 | if (inArchOptions != NULL) { |
michael@0 | 419 | switch (inArchOptions->archOption) { |
michael@0 | 420 | case crmfEncryptedPrivateKey: |
michael@0 | 421 | crmf_destroy_encrypted_key(&inArchOptions->option.encryptedKey, |
michael@0 | 422 | PR_FALSE); |
michael@0 | 423 | break; |
michael@0 | 424 | case crmfKeyGenParameters: |
michael@0 | 425 | case crmfArchiveRemGenPrivKey: |
michael@0 | 426 | /* This is a union, so having a pointer to one is like |
michael@0 | 427 | * having a pointer to both. |
michael@0 | 428 | */ |
michael@0 | 429 | SECITEM_FreeItem(&inArchOptions->option.keyGenParameters, |
michael@0 | 430 | PR_FALSE); |
michael@0 | 431 | break; |
michael@0 | 432 | case crmfNoArchiveOptions: |
michael@0 | 433 | break; |
michael@0 | 434 | } |
michael@0 | 435 | if (freeit) { |
michael@0 | 436 | PORT_Free(inArchOptions); |
michael@0 | 437 | } |
michael@0 | 438 | } |
michael@0 | 439 | return SECSuccess; |
michael@0 | 440 | } |
michael@0 | 441 | |
michael@0 | 442 | SECStatus |
michael@0 | 443 | CRMF_DestroyPKIArchiveOptions(CRMFPKIArchiveOptions *inArchOptions) |
michael@0 | 444 | { |
michael@0 | 445 | return crmf_destroy_pkiarchiveoptions(inArchOptions, PR_TRUE); |
michael@0 | 446 | } |
michael@0 | 447 | |
michael@0 | 448 | static CK_MECHANISM_TYPE |
michael@0 | 449 | crmf_get_non_pad_mechanism(CK_MECHANISM_TYPE type) |
michael@0 | 450 | { |
michael@0 | 451 | switch (type) { |
michael@0 | 452 | case CKM_DES3_CBC_PAD: |
michael@0 | 453 | return CKM_DES3_CBC; |
michael@0 | 454 | case CKM_CAST5_CBC_PAD: |
michael@0 | 455 | return CKM_CAST5_CBC; |
michael@0 | 456 | case CKM_DES_CBC_PAD: |
michael@0 | 457 | return CKM_DES_CBC; |
michael@0 | 458 | case CKM_IDEA_CBC_PAD: |
michael@0 | 459 | return CKM_IDEA_CBC; |
michael@0 | 460 | case CKM_CAST3_CBC_PAD: |
michael@0 | 461 | return CKM_CAST3_CBC; |
michael@0 | 462 | case CKM_CAST_CBC_PAD: |
michael@0 | 463 | return CKM_CAST_CBC; |
michael@0 | 464 | case CKM_RC5_CBC_PAD: |
michael@0 | 465 | return CKM_RC5_CBC; |
michael@0 | 466 | case CKM_RC2_CBC_PAD: |
michael@0 | 467 | return CKM_RC2_CBC; |
michael@0 | 468 | case CKM_CDMF_CBC_PAD: |
michael@0 | 469 | return CKM_CDMF_CBC; |
michael@0 | 470 | } |
michael@0 | 471 | return type; |
michael@0 | 472 | } |
michael@0 | 473 | |
michael@0 | 474 | static CK_MECHANISM_TYPE |
michael@0 | 475 | crmf_get_pad_mech_from_tag(SECOidTag oidTag) |
michael@0 | 476 | { |
michael@0 | 477 | CK_MECHANISM_TYPE mechType; |
michael@0 | 478 | SECOidData *oidData; |
michael@0 | 479 | |
michael@0 | 480 | oidData = SECOID_FindOIDByTag(oidTag); |
michael@0 | 481 | mechType = (CK_MECHANISM_TYPE)oidData->mechanism; |
michael@0 | 482 | return PK11_GetPadMechanism(mechType); |
michael@0 | 483 | } |
michael@0 | 484 | |
michael@0 | 485 | static CK_MECHANISM_TYPE |
michael@0 | 486 | crmf_get_best_privkey_wrap_mechanism(PK11SlotInfo *slot) |
michael@0 | 487 | { |
michael@0 | 488 | CK_MECHANISM_TYPE privKeyPadMechs[] = { CKM_DES3_CBC_PAD, |
michael@0 | 489 | CKM_CAST5_CBC_PAD, |
michael@0 | 490 | CKM_DES_CBC_PAD, |
michael@0 | 491 | CKM_IDEA_CBC_PAD, |
michael@0 | 492 | CKM_CAST3_CBC_PAD, |
michael@0 | 493 | CKM_CAST_CBC_PAD, |
michael@0 | 494 | CKM_RC5_CBC_PAD, |
michael@0 | 495 | CKM_RC2_CBC_PAD, |
michael@0 | 496 | CKM_CDMF_CBC_PAD }; |
michael@0 | 497 | int mechCount = sizeof(privKeyPadMechs)/sizeof(privKeyPadMechs[0]); |
michael@0 | 498 | int i; |
michael@0 | 499 | |
michael@0 | 500 | for (i=0; i < mechCount; i++) { |
michael@0 | 501 | if (PK11_DoesMechanism(slot, privKeyPadMechs[i])) { |
michael@0 | 502 | return privKeyPadMechs[i]; |
michael@0 | 503 | } |
michael@0 | 504 | } |
michael@0 | 505 | return CKM_INVALID_MECHANISM; |
michael@0 | 506 | } |
michael@0 | 507 | |
michael@0 | 508 | CK_MECHANISM_TYPE |
michael@0 | 509 | CRMF_GetBestWrapPadMechanism(PK11SlotInfo *slot) |
michael@0 | 510 | { |
michael@0 | 511 | return crmf_get_best_privkey_wrap_mechanism(slot); |
michael@0 | 512 | } |
michael@0 | 513 | |
michael@0 | 514 | static SECItem* |
michael@0 | 515 | crmf_get_iv(CK_MECHANISM_TYPE mechType) |
michael@0 | 516 | { |
michael@0 | 517 | int iv_size = PK11_GetIVLength(mechType); |
michael@0 | 518 | SECItem *iv; |
michael@0 | 519 | SECStatus rv; |
michael@0 | 520 | |
michael@0 | 521 | iv = PORT_ZNew(SECItem); |
michael@0 | 522 | if (iv == NULL) { |
michael@0 | 523 | return NULL; |
michael@0 | 524 | } |
michael@0 | 525 | if (iv_size == 0) { |
michael@0 | 526 | iv->data = NULL; |
michael@0 | 527 | iv->len = 0; |
michael@0 | 528 | return iv; |
michael@0 | 529 | } |
michael@0 | 530 | iv->data = PORT_NewArray(unsigned char, iv_size); |
michael@0 | 531 | if (iv->data == NULL) { |
michael@0 | 532 | iv->len = 0; |
michael@0 | 533 | return iv; |
michael@0 | 534 | } |
michael@0 | 535 | iv->len = iv_size; |
michael@0 | 536 | rv = PK11_GenerateRandom(iv->data, iv->len); |
michael@0 | 537 | if (rv != SECSuccess) { |
michael@0 | 538 | PORT_Free(iv->data); |
michael@0 | 539 | iv->data = NULL; |
michael@0 | 540 | iv->len = 0; |
michael@0 | 541 | } |
michael@0 | 542 | return iv; |
michael@0 | 543 | } |
michael@0 | 544 | |
michael@0 | 545 | SECItem* |
michael@0 | 546 | CRMF_GetIVFromMechanism(CK_MECHANISM_TYPE mechType) |
michael@0 | 547 | { |
michael@0 | 548 | return crmf_get_iv(mechType); |
michael@0 | 549 | } |
michael@0 | 550 | |
michael@0 | 551 | CK_MECHANISM_TYPE |
michael@0 | 552 | crmf_get_mechanism_from_public_key(SECKEYPublicKey *inPubKey) |
michael@0 | 553 | { |
michael@0 | 554 | CERTSubjectPublicKeyInfo *spki = NULL; |
michael@0 | 555 | SECOidTag tag; |
michael@0 | 556 | |
michael@0 | 557 | |
michael@0 | 558 | spki = SECKEY_CreateSubjectPublicKeyInfo(inPubKey); |
michael@0 | 559 | if (spki == NULL) { |
michael@0 | 560 | return CKM_INVALID_MECHANISM; |
michael@0 | 561 | } |
michael@0 | 562 | tag = SECOID_FindOIDTag(&spki->algorithm.algorithm); |
michael@0 | 563 | SECKEY_DestroySubjectPublicKeyInfo(spki); |
michael@0 | 564 | spki = NULL; |
michael@0 | 565 | return PK11_AlgtagToMechanism(tag); |
michael@0 | 566 | } |
michael@0 | 567 | |
michael@0 | 568 | SECItem* |
michael@0 | 569 | crmf_get_public_value(SECKEYPublicKey *pubKey, SECItem *dest) |
michael@0 | 570 | { |
michael@0 | 571 | SECItem *src; |
michael@0 | 572 | |
michael@0 | 573 | switch(pubKey->keyType) { |
michael@0 | 574 | case dsaKey: |
michael@0 | 575 | src = &pubKey->u.dsa.publicValue; |
michael@0 | 576 | break; |
michael@0 | 577 | case rsaKey: |
michael@0 | 578 | src = &pubKey->u.rsa.modulus; |
michael@0 | 579 | break; |
michael@0 | 580 | case dhKey: |
michael@0 | 581 | src = &pubKey->u.dh.publicValue; |
michael@0 | 582 | break; |
michael@0 | 583 | default: |
michael@0 | 584 | src = NULL; |
michael@0 | 585 | break; |
michael@0 | 586 | } |
michael@0 | 587 | if (!src) { |
michael@0 | 588 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
michael@0 | 589 | return NULL; |
michael@0 | 590 | } |
michael@0 | 591 | |
michael@0 | 592 | if (dest != NULL) { |
michael@0 | 593 | SECStatus rv = SECITEM_CopyItem(NULL, dest, src); |
michael@0 | 594 | if (rv != SECSuccess) { |
michael@0 | 595 | dest = NULL; |
michael@0 | 596 | } |
michael@0 | 597 | } else { |
michael@0 | 598 | dest = SECITEM_ArenaDupItem(NULL, src); |
michael@0 | 599 | } |
michael@0 | 600 | return dest; |
michael@0 | 601 | } |
michael@0 | 602 | |
michael@0 | 603 | static SECItem* |
michael@0 | 604 | crmf_decode_params(SECItem *inParams) |
michael@0 | 605 | { |
michael@0 | 606 | SECItem *params; |
michael@0 | 607 | SECStatus rv = SECFailure; |
michael@0 | 608 | PLArenaPool *poolp; |
michael@0 | 609 | |
michael@0 | 610 | poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE); |
michael@0 | 611 | if (poolp == NULL) { |
michael@0 | 612 | return NULL; |
michael@0 | 613 | } |
michael@0 | 614 | |
michael@0 | 615 | params = PORT_ArenaZNew(poolp, SECItem); |
michael@0 | 616 | if (params) { |
michael@0 | 617 | rv = SEC_ASN1DecodeItem(poolp, params, |
michael@0 | 618 | SEC_ASN1_GET(SEC_OctetStringTemplate), |
michael@0 | 619 | inParams); |
michael@0 | 620 | } |
michael@0 | 621 | params = (rv == SECSuccess) ? SECITEM_ArenaDupItem(NULL, params) : NULL; |
michael@0 | 622 | PORT_FreeArena(poolp, PR_FALSE); |
michael@0 | 623 | return params; |
michael@0 | 624 | } |
michael@0 | 625 | |
michael@0 | 626 | static int |
michael@0 | 627 | crmf_get_key_size_from_mech(CK_MECHANISM_TYPE mechType) |
michael@0 | 628 | { |
michael@0 | 629 | CK_MECHANISM_TYPE keyGen = PK11_GetKeyGen(mechType); |
michael@0 | 630 | |
michael@0 | 631 | switch (keyGen) { |
michael@0 | 632 | case CKM_CDMF_KEY_GEN: |
michael@0 | 633 | case CKM_DES_KEY_GEN: |
michael@0 | 634 | return 8; |
michael@0 | 635 | case CKM_DES2_KEY_GEN: |
michael@0 | 636 | return 16; |
michael@0 | 637 | case CKM_DES3_KEY_GEN: |
michael@0 | 638 | return 24; |
michael@0 | 639 | } |
michael@0 | 640 | return 0; |
michael@0 | 641 | } |
michael@0 | 642 | |
michael@0 | 643 | SECStatus |
michael@0 | 644 | crmf_encrypted_value_unwrap_priv_key(PLArenaPool *poolp, |
michael@0 | 645 | CRMFEncryptedValue *encValue, |
michael@0 | 646 | SECKEYPrivateKey *privKey, |
michael@0 | 647 | SECKEYPublicKey *newPubKey, |
michael@0 | 648 | SECItem *nickname, |
michael@0 | 649 | PK11SlotInfo *slot, |
michael@0 | 650 | unsigned char keyUsage, |
michael@0 | 651 | SECKEYPrivateKey **unWrappedKey, |
michael@0 | 652 | void *wincx) |
michael@0 | 653 | { |
michael@0 | 654 | PK11SymKey *wrappingKey = NULL; |
michael@0 | 655 | CK_MECHANISM_TYPE wrapMechType; |
michael@0 | 656 | SECOidTag oidTag; |
michael@0 | 657 | SECItem *params = NULL, *publicValue = NULL; |
michael@0 | 658 | int keySize, origLen; |
michael@0 | 659 | CK_KEY_TYPE keyType; |
michael@0 | 660 | CK_ATTRIBUTE_TYPE *usage = NULL; |
michael@0 | 661 | CK_ATTRIBUTE_TYPE rsaUsage[] = { |
michael@0 | 662 | CKA_UNWRAP, CKA_DECRYPT, CKA_SIGN, CKA_SIGN_RECOVER }; |
michael@0 | 663 | CK_ATTRIBUTE_TYPE dsaUsage[] = { CKA_SIGN }; |
michael@0 | 664 | CK_ATTRIBUTE_TYPE dhUsage[] = { CKA_DERIVE }; |
michael@0 | 665 | int usageCount = 0; |
michael@0 | 666 | |
michael@0 | 667 | oidTag = SECOID_GetAlgorithmTag(encValue->symmAlg); |
michael@0 | 668 | wrapMechType = crmf_get_pad_mech_from_tag(oidTag); |
michael@0 | 669 | keySize = crmf_get_key_size_from_mech(wrapMechType); |
michael@0 | 670 | wrappingKey = PK11_PubUnwrapSymKey(privKey, &encValue->encSymmKey, |
michael@0 | 671 | wrapMechType, CKA_UNWRAP, keySize); |
michael@0 | 672 | if (wrappingKey == NULL) { |
michael@0 | 673 | goto loser; |
michael@0 | 674 | }/* Make the length a byte length instead of bit length*/ |
michael@0 | 675 | params = (encValue->symmAlg != NULL) ? |
michael@0 | 676 | crmf_decode_params(&encValue->symmAlg->parameters) : NULL; |
michael@0 | 677 | origLen = encValue->encValue.len; |
michael@0 | 678 | encValue->encValue.len = CRMF_BITS_TO_BYTES(origLen); |
michael@0 | 679 | publicValue = crmf_get_public_value(newPubKey, NULL); |
michael@0 | 680 | switch(newPubKey->keyType) { |
michael@0 | 681 | default: |
michael@0 | 682 | case rsaKey: |
michael@0 | 683 | keyType = CKK_RSA; |
michael@0 | 684 | switch (keyUsage & (KU_KEY_ENCIPHERMENT|KU_DIGITAL_SIGNATURE)) { |
michael@0 | 685 | case KU_KEY_ENCIPHERMENT: |
michael@0 | 686 | usage = rsaUsage; |
michael@0 | 687 | usageCount = 2; |
michael@0 | 688 | break; |
michael@0 | 689 | case KU_DIGITAL_SIGNATURE: |
michael@0 | 690 | usage = &rsaUsage[2]; |
michael@0 | 691 | usageCount = 2; |
michael@0 | 692 | break; |
michael@0 | 693 | case KU_KEY_ENCIPHERMENT|KU_DIGITAL_SIGNATURE: |
michael@0 | 694 | case 0: /* default to everything */ |
michael@0 | 695 | usage = rsaUsage; |
michael@0 | 696 | usageCount = 4; |
michael@0 | 697 | break; |
michael@0 | 698 | } |
michael@0 | 699 | break; |
michael@0 | 700 | case dhKey: |
michael@0 | 701 | keyType = CKK_DH; |
michael@0 | 702 | usage = dhUsage; |
michael@0 | 703 | usageCount = sizeof(dhUsage)/sizeof(dhUsage[0]); |
michael@0 | 704 | break; |
michael@0 | 705 | case dsaKey: |
michael@0 | 706 | keyType = CKK_DSA; |
michael@0 | 707 | usage = dsaUsage; |
michael@0 | 708 | usageCount = sizeof(dsaUsage)/sizeof(dsaUsage[0]); |
michael@0 | 709 | break; |
michael@0 | 710 | } |
michael@0 | 711 | PORT_Assert(usage != NULL); |
michael@0 | 712 | PORT_Assert(usageCount != 0); |
michael@0 | 713 | *unWrappedKey = PK11_UnwrapPrivKey(slot, wrappingKey, wrapMechType, params, |
michael@0 | 714 | &encValue->encValue, nickname, |
michael@0 | 715 | publicValue, PR_TRUE,PR_TRUE, |
michael@0 | 716 | keyType, usage, usageCount, wincx); |
michael@0 | 717 | encValue->encValue.len = origLen; |
michael@0 | 718 | if (*unWrappedKey == NULL) { |
michael@0 | 719 | goto loser; |
michael@0 | 720 | } |
michael@0 | 721 | SECITEM_FreeItem (publicValue, PR_TRUE); |
michael@0 | 722 | if (params!= NULL) { |
michael@0 | 723 | SECITEM_FreeItem(params, PR_TRUE); |
michael@0 | 724 | } |
michael@0 | 725 | PK11_FreeSymKey(wrappingKey); |
michael@0 | 726 | return SECSuccess; |
michael@0 | 727 | loser: |
michael@0 | 728 | *unWrappedKey = NULL; |
michael@0 | 729 | return SECFailure; |
michael@0 | 730 | } |
michael@0 | 731 | |
michael@0 | 732 | CRMFEncryptedValue * |
michael@0 | 733 | crmf_create_encrypted_value_wrapped_privkey(SECKEYPrivateKey *inPrivKey, |
michael@0 | 734 | SECKEYPublicKey *inCAKey, |
michael@0 | 735 | CRMFEncryptedValue *destValue) |
michael@0 | 736 | { |
michael@0 | 737 | SECItem wrappedPrivKey, wrappedSymKey; |
michael@0 | 738 | SECItem encodedParam, *dummy; |
michael@0 | 739 | SECStatus rv; |
michael@0 | 740 | CK_MECHANISM_TYPE pubMechType, symKeyType; |
michael@0 | 741 | unsigned char *wrappedSymKeyBits; |
michael@0 | 742 | unsigned char *wrappedPrivKeyBits; |
michael@0 | 743 | SECItem *iv = NULL; |
michael@0 | 744 | SECOidTag tag; |
michael@0 | 745 | PK11SymKey *symKey; |
michael@0 | 746 | PK11SlotInfo *slot; |
michael@0 | 747 | SECAlgorithmID *symmAlg; |
michael@0 | 748 | CRMFEncryptedValue *myEncrValue = NULL; |
michael@0 | 749 | |
michael@0 | 750 | encodedParam.data = NULL; |
michael@0 | 751 | wrappedSymKeyBits = PORT_NewArray(unsigned char, MAX_WRAPPED_KEY_LEN); |
michael@0 | 752 | wrappedPrivKeyBits = PORT_NewArray(unsigned char, MAX_WRAPPED_KEY_LEN); |
michael@0 | 753 | if (wrappedSymKeyBits == NULL || wrappedPrivKeyBits == NULL) { |
michael@0 | 754 | goto loser; |
michael@0 | 755 | } |
michael@0 | 756 | if (destValue == NULL) { |
michael@0 | 757 | myEncrValue = destValue = PORT_ZNew(CRMFEncryptedValue); |
michael@0 | 758 | if (destValue == NULL) { |
michael@0 | 759 | goto loser; |
michael@0 | 760 | } |
michael@0 | 761 | } |
michael@0 | 762 | |
michael@0 | 763 | pubMechType = crmf_get_mechanism_from_public_key(inCAKey); |
michael@0 | 764 | if (pubMechType == CKM_INVALID_MECHANISM) { |
michael@0 | 765 | /* XXX I should probably do something here for non-RSA |
michael@0 | 766 | * keys that are in certs. (ie DSA) |
michael@0 | 767 | * XXX or at least SET AN ERROR CODE. |
michael@0 | 768 | */ |
michael@0 | 769 | goto loser; |
michael@0 | 770 | } |
michael@0 | 771 | slot = inPrivKey->pkcs11Slot; |
michael@0 | 772 | PORT_Assert(slot != NULL); |
michael@0 | 773 | symKeyType = crmf_get_best_privkey_wrap_mechanism(slot); |
michael@0 | 774 | symKey = PK11_KeyGen(slot, symKeyType, NULL, 0, NULL); |
michael@0 | 775 | if (symKey == NULL) { |
michael@0 | 776 | goto loser; |
michael@0 | 777 | } |
michael@0 | 778 | |
michael@0 | 779 | wrappedSymKey.data = wrappedSymKeyBits; |
michael@0 | 780 | wrappedSymKey.len = MAX_WRAPPED_KEY_LEN; |
michael@0 | 781 | rv = PK11_PubWrapSymKey(pubMechType, inCAKey, symKey, &wrappedSymKey); |
michael@0 | 782 | if (rv != SECSuccess) { |
michael@0 | 783 | goto loser; |
michael@0 | 784 | } |
michael@0 | 785 | /* Make the length of the result a Bit String length. */ |
michael@0 | 786 | wrappedSymKey.len <<= 3; |
michael@0 | 787 | |
michael@0 | 788 | wrappedPrivKey.data = wrappedPrivKeyBits; |
michael@0 | 789 | wrappedPrivKey.len = MAX_WRAPPED_KEY_LEN; |
michael@0 | 790 | iv = crmf_get_iv(symKeyType); |
michael@0 | 791 | rv = PK11_WrapPrivKey(slot, symKey, inPrivKey, symKeyType, iv, |
michael@0 | 792 | &wrappedPrivKey, NULL); |
michael@0 | 793 | PK11_FreeSymKey(symKey); |
michael@0 | 794 | if (rv != SECSuccess) { |
michael@0 | 795 | goto loser; |
michael@0 | 796 | } |
michael@0 | 797 | /* Make the length of the result a Bit String length. */ |
michael@0 | 798 | wrappedPrivKey.len <<= 3; |
michael@0 | 799 | rv = crmf_make_bitstring_copy(NULL, |
michael@0 | 800 | &destValue->encValue, |
michael@0 | 801 | &wrappedPrivKey); |
michael@0 | 802 | if (rv != SECSuccess) { |
michael@0 | 803 | goto loser; |
michael@0 | 804 | } |
michael@0 | 805 | |
michael@0 | 806 | rv = crmf_make_bitstring_copy(NULL, |
michael@0 | 807 | &destValue->encSymmKey, |
michael@0 | 808 | &wrappedSymKey); |
michael@0 | 809 | if (rv != SECSuccess) { |
michael@0 | 810 | goto loser; |
michael@0 | 811 | } |
michael@0 | 812 | destValue->symmAlg = symmAlg = PORT_ZNew(SECAlgorithmID); |
michael@0 | 813 | if (symmAlg == NULL) { |
michael@0 | 814 | goto loser; |
michael@0 | 815 | } |
michael@0 | 816 | |
michael@0 | 817 | dummy = SEC_ASN1EncodeItem(NULL, &encodedParam, iv, |
michael@0 | 818 | SEC_ASN1_GET(SEC_OctetStringTemplate)); |
michael@0 | 819 | if (dummy != &encodedParam) { |
michael@0 | 820 | SECITEM_FreeItem(dummy, PR_TRUE); |
michael@0 | 821 | goto loser; |
michael@0 | 822 | } |
michael@0 | 823 | |
michael@0 | 824 | symKeyType = crmf_get_non_pad_mechanism(symKeyType); |
michael@0 | 825 | tag = PK11_MechanismToAlgtag(symKeyType); |
michael@0 | 826 | rv = SECOID_SetAlgorithmID(NULL, symmAlg, tag, &encodedParam); |
michael@0 | 827 | if (rv != SECSuccess) { |
michael@0 | 828 | goto loser; |
michael@0 | 829 | } |
michael@0 | 830 | SECITEM_FreeItem(&encodedParam, PR_FALSE); |
michael@0 | 831 | PORT_Free(wrappedPrivKeyBits); |
michael@0 | 832 | PORT_Free(wrappedSymKeyBits); |
michael@0 | 833 | SECITEM_FreeItem(iv, PR_TRUE); |
michael@0 | 834 | return destValue; |
michael@0 | 835 | loser: |
michael@0 | 836 | if (iv != NULL) { |
michael@0 | 837 | SECITEM_FreeItem(iv, PR_TRUE); |
michael@0 | 838 | } |
michael@0 | 839 | if (myEncrValue != NULL) { |
michael@0 | 840 | crmf_destroy_encrypted_value(myEncrValue, PR_TRUE); |
michael@0 | 841 | } |
michael@0 | 842 | if (wrappedSymKeyBits != NULL) { |
michael@0 | 843 | PORT_Free(wrappedSymKeyBits); |
michael@0 | 844 | } |
michael@0 | 845 | if (wrappedPrivKeyBits != NULL) { |
michael@0 | 846 | PORT_Free(wrappedPrivKeyBits); |
michael@0 | 847 | } |
michael@0 | 848 | if (encodedParam.data != NULL) { |
michael@0 | 849 | SECITEM_FreeItem(&encodedParam, PR_FALSE); |
michael@0 | 850 | } |
michael@0 | 851 | return NULL; |
michael@0 | 852 | } |
michael@0 | 853 | |
michael@0 | 854 | CRMFEncryptedKey* |
michael@0 | 855 | CRMF_CreateEncryptedKeyWithEncryptedValue (SECKEYPrivateKey *inPrivKey, |
michael@0 | 856 | CERTCertificate *inCACert) |
michael@0 | 857 | { |
michael@0 | 858 | SECKEYPublicKey *caPubKey = NULL; |
michael@0 | 859 | CRMFEncryptedKey *encKey = NULL; |
michael@0 | 860 | CRMFEncryptedValue *dummy; |
michael@0 | 861 | |
michael@0 | 862 | PORT_Assert(inPrivKey != NULL && inCACert != NULL); |
michael@0 | 863 | if (inPrivKey == NULL || inCACert == NULL) { |
michael@0 | 864 | return NULL; |
michael@0 | 865 | } |
michael@0 | 866 | |
michael@0 | 867 | caPubKey = CERT_ExtractPublicKey(inCACert); |
michael@0 | 868 | if (caPubKey == NULL) { |
michael@0 | 869 | goto loser; |
michael@0 | 870 | } |
michael@0 | 871 | |
michael@0 | 872 | encKey = PORT_ZNew(CRMFEncryptedKey); |
michael@0 | 873 | if (encKey == NULL) { |
michael@0 | 874 | goto loser; |
michael@0 | 875 | } |
michael@0 | 876 | dummy = crmf_create_encrypted_value_wrapped_privkey(inPrivKey, |
michael@0 | 877 | caPubKey, |
michael@0 | 878 | &encKey->value.encryptedValue); |
michael@0 | 879 | PORT_Assert(dummy == &encKey->value.encryptedValue); |
michael@0 | 880 | /* We won't add the der value here, but rather when it |
michael@0 | 881 | * becomes part of a certificate request. |
michael@0 | 882 | */ |
michael@0 | 883 | SECKEY_DestroyPublicKey(caPubKey); |
michael@0 | 884 | encKey->encKeyChoice = crmfEncryptedValueChoice; |
michael@0 | 885 | return encKey; |
michael@0 | 886 | loser: |
michael@0 | 887 | if (encKey != NULL) { |
michael@0 | 888 | CRMF_DestroyEncryptedKey(encKey); |
michael@0 | 889 | } |
michael@0 | 890 | if (caPubKey != NULL) { |
michael@0 | 891 | SECKEY_DestroyPublicKey(caPubKey); |
michael@0 | 892 | } |
michael@0 | 893 | return NULL; |
michael@0 | 894 | } |
michael@0 | 895 | |
michael@0 | 896 | SECStatus |
michael@0 | 897 | CRMF_DestroyEncryptedKey(CRMFEncryptedKey *inEncrKey) |
michael@0 | 898 | { |
michael@0 | 899 | return crmf_destroy_encrypted_key(inEncrKey, PR_TRUE); |
michael@0 | 900 | } |
michael@0 | 901 | |
michael@0 | 902 | SECStatus |
michael@0 | 903 | crmf_copy_pkiarchiveoptions(PLArenaPool *poolp, |
michael@0 | 904 | CRMFPKIArchiveOptions *destOpt, |
michael@0 | 905 | CRMFPKIArchiveOptions *srcOpt) |
michael@0 | 906 | { |
michael@0 | 907 | SECStatus rv; |
michael@0 | 908 | destOpt->archOption = srcOpt->archOption; |
michael@0 | 909 | switch (srcOpt->archOption) { |
michael@0 | 910 | case crmfEncryptedPrivateKey: |
michael@0 | 911 | rv = crmf_copy_encryptedkey(poolp, |
michael@0 | 912 | &srcOpt->option.encryptedKey, |
michael@0 | 913 | &destOpt->option.encryptedKey); |
michael@0 | 914 | break; |
michael@0 | 915 | case crmfKeyGenParameters: |
michael@0 | 916 | case crmfArchiveRemGenPrivKey: |
michael@0 | 917 | /* We've got a union, so having a pointer to one is just |
michael@0 | 918 | * like having a pointer to the other one. |
michael@0 | 919 | */ |
michael@0 | 920 | rv = SECITEM_CopyItem(poolp, |
michael@0 | 921 | &destOpt->option.keyGenParameters, |
michael@0 | 922 | &srcOpt->option.keyGenParameters); |
michael@0 | 923 | break; |
michael@0 | 924 | default: |
michael@0 | 925 | rv = SECFailure; |
michael@0 | 926 | } |
michael@0 | 927 | return rv; |
michael@0 | 928 | } |
michael@0 | 929 | |
michael@0 | 930 | static SECStatus |
michael@0 | 931 | crmf_check_and_adjust_archoption(CRMFControl *inControl) |
michael@0 | 932 | { |
michael@0 | 933 | CRMFPKIArchiveOptions *options; |
michael@0 | 934 | |
michael@0 | 935 | options = &inControl->value.archiveOptions; |
michael@0 | 936 | if (options->archOption == crmfNoArchiveOptions) { |
michael@0 | 937 | /* It hasn't been set, so figure it out from the |
michael@0 | 938 | * der. |
michael@0 | 939 | */ |
michael@0 | 940 | switch (inControl->derValue.data[0] & 0x0f) { |
michael@0 | 941 | case 0: |
michael@0 | 942 | options->archOption = crmfEncryptedPrivateKey; |
michael@0 | 943 | break; |
michael@0 | 944 | case 1: |
michael@0 | 945 | options->archOption = crmfKeyGenParameters; |
michael@0 | 946 | break; |
michael@0 | 947 | case 2: |
michael@0 | 948 | options->archOption = crmfArchiveRemGenPrivKey; |
michael@0 | 949 | break; |
michael@0 | 950 | default: |
michael@0 | 951 | /* We've got bad DER. Return an error. */ |
michael@0 | 952 | return SECFailure; |
michael@0 | 953 | } |
michael@0 | 954 | } |
michael@0 | 955 | return SECSuccess; |
michael@0 | 956 | } |
michael@0 | 957 | |
michael@0 | 958 | static const SEC_ASN1Template * |
michael@0 | 959 | crmf_get_pkiarchive_subtemplate(CRMFControl *inControl) |
michael@0 | 960 | { |
michael@0 | 961 | const SEC_ASN1Template *retTemplate; |
michael@0 | 962 | SECStatus rv; |
michael@0 | 963 | /* |
michael@0 | 964 | * We could be in the process of decoding, in which case the |
michael@0 | 965 | * archOption field will not be set. Let's check it and set |
michael@0 | 966 | * it accordingly. |
michael@0 | 967 | */ |
michael@0 | 968 | |
michael@0 | 969 | rv = crmf_check_and_adjust_archoption(inControl); |
michael@0 | 970 | if (rv != SECSuccess) { |
michael@0 | 971 | return NULL; |
michael@0 | 972 | } |
michael@0 | 973 | |
michael@0 | 974 | switch (inControl->value.archiveOptions.archOption) { |
michael@0 | 975 | case crmfEncryptedPrivateKey: |
michael@0 | 976 | retTemplate = CRMFEncryptedKeyWithEncryptedValueTemplate; |
michael@0 | 977 | inControl->value.archiveOptions.option.encryptedKey.encKeyChoice = |
michael@0 | 978 | crmfEncryptedValueChoice; |
michael@0 | 979 | break; |
michael@0 | 980 | default: |
michael@0 | 981 | retTemplate = NULL; |
michael@0 | 982 | } |
michael@0 | 983 | return retTemplate; |
michael@0 | 984 | } |
michael@0 | 985 | |
michael@0 | 986 | const SEC_ASN1Template* |
michael@0 | 987 | crmf_get_pkiarchiveoptions_subtemplate(CRMFControl *inControl) |
michael@0 | 988 | { |
michael@0 | 989 | const SEC_ASN1Template *retTemplate; |
michael@0 | 990 | |
michael@0 | 991 | switch (inControl->tag) { |
michael@0 | 992 | case SEC_OID_PKIX_REGCTRL_REGTOKEN: |
michael@0 | 993 | case SEC_OID_PKIX_REGCTRL_AUTHENTICATOR: |
michael@0 | 994 | retTemplate = SEC_ASN1_GET(SEC_UTF8StringTemplate); |
michael@0 | 995 | break; |
michael@0 | 996 | case SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS: |
michael@0 | 997 | retTemplate = crmf_get_pkiarchive_subtemplate(inControl); |
michael@0 | 998 | break; |
michael@0 | 999 | case SEC_OID_PKIX_REGCTRL_PKIPUBINFO: |
michael@0 | 1000 | case SEC_OID_PKIX_REGCTRL_OLD_CERT_ID: |
michael@0 | 1001 | case SEC_OID_PKIX_REGCTRL_PROTOCOL_ENC_KEY: |
michael@0 | 1002 | /* We don't support these controls, so we fail for now.*/ |
michael@0 | 1003 | retTemplate = NULL; |
michael@0 | 1004 | break; |
michael@0 | 1005 | default: |
michael@0 | 1006 | retTemplate = NULL; |
michael@0 | 1007 | } |
michael@0 | 1008 | return retTemplate; |
michael@0 | 1009 | } |
michael@0 | 1010 | |
michael@0 | 1011 | static SECStatus |
michael@0 | 1012 | crmf_encode_pkiarchiveoptions(PLArenaPool *poolp, CRMFControl *inControl) |
michael@0 | 1013 | { |
michael@0 | 1014 | const SEC_ASN1Template *asn1Template; |
michael@0 | 1015 | |
michael@0 | 1016 | asn1Template = crmf_get_pkiarchiveoptions_subtemplate(inControl); |
michael@0 | 1017 | /* We've got a union, so passing a pointer to one element of the |
michael@0 | 1018 | * union, is the same as passing a pointer to any of the other |
michael@0 | 1019 | * members of the union. |
michael@0 | 1020 | */ |
michael@0 | 1021 | SEC_ASN1EncodeItem(poolp, &inControl->derValue, |
michael@0 | 1022 | &inControl->value.archiveOptions, asn1Template); |
michael@0 | 1023 | |
michael@0 | 1024 | if (inControl->derValue.data == NULL) { |
michael@0 | 1025 | goto loser; |
michael@0 | 1026 | } |
michael@0 | 1027 | return SECSuccess; |
michael@0 | 1028 | loser: |
michael@0 | 1029 | return SECFailure; |
michael@0 | 1030 | } |
michael@0 | 1031 | |
michael@0 | 1032 | SECStatus |
michael@0 | 1033 | CRMF_CertRequestSetPKIArchiveOptions(CRMFCertRequest *inCertReq, |
michael@0 | 1034 | CRMFPKIArchiveOptions *inOptions) |
michael@0 | 1035 | { |
michael@0 | 1036 | CRMFControl *newControl; |
michael@0 | 1037 | PLArenaPool *poolp; |
michael@0 | 1038 | SECStatus rv; |
michael@0 | 1039 | void *mark; |
michael@0 | 1040 | |
michael@0 | 1041 | PORT_Assert(inCertReq != NULL && inOptions != NULL); |
michael@0 | 1042 | if (inCertReq == NULL || inOptions == NULL) { |
michael@0 | 1043 | return SECFailure; |
michael@0 | 1044 | } |
michael@0 | 1045 | poolp = inCertReq->poolp; |
michael@0 | 1046 | mark = PORT_ArenaMark(poolp); |
michael@0 | 1047 | rv = crmf_add_new_control(inCertReq, |
michael@0 | 1048 | SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS, |
michael@0 | 1049 | &newControl); |
michael@0 | 1050 | if (rv != SECSuccess) { |
michael@0 | 1051 | goto loser; |
michael@0 | 1052 | } |
michael@0 | 1053 | |
michael@0 | 1054 | rv = crmf_copy_pkiarchiveoptions(poolp, |
michael@0 | 1055 | &newControl->value.archiveOptions, |
michael@0 | 1056 | inOptions); |
michael@0 | 1057 | if (rv != SECSuccess) { |
michael@0 | 1058 | goto loser; |
michael@0 | 1059 | } |
michael@0 | 1060 | |
michael@0 | 1061 | rv = crmf_encode_pkiarchiveoptions(poolp, newControl); |
michael@0 | 1062 | if (rv != SECSuccess) { |
michael@0 | 1063 | goto loser; |
michael@0 | 1064 | } |
michael@0 | 1065 | PORT_ArenaUnmark(poolp, mark); |
michael@0 | 1066 | return SECSuccess; |
michael@0 | 1067 | loser: |
michael@0 | 1068 | PORT_ArenaRelease(poolp, mark); |
michael@0 | 1069 | return SECFailure; |
michael@0 | 1070 | } |
michael@0 | 1071 | |
michael@0 | 1072 | static SECStatus |
michael@0 | 1073 | crmf_destroy_control(CRMFControl *inControl, PRBool freeit) |
michael@0 | 1074 | { |
michael@0 | 1075 | PORT_Assert(inControl != NULL); |
michael@0 | 1076 | if (inControl != NULL) { |
michael@0 | 1077 | SECITEM_FreeItem(&inControl->derTag, PR_FALSE); |
michael@0 | 1078 | SECITEM_FreeItem(&inControl->derValue, PR_FALSE); |
michael@0 | 1079 | /* None of the other tags require special processing at |
michael@0 | 1080 | * the moment when freeing because they are not supported, |
michael@0 | 1081 | * but if/when they are, add the necessary routines here. |
michael@0 | 1082 | * If all controls are supported, then every member of the |
michael@0 | 1083 | * union inControl->value will have a case that deals with |
michael@0 | 1084 | * it in the following switch statement. |
michael@0 | 1085 | */ |
michael@0 | 1086 | switch (inControl->tag) { |
michael@0 | 1087 | case SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS: |
michael@0 | 1088 | crmf_destroy_pkiarchiveoptions(&inControl->value.archiveOptions, |
michael@0 | 1089 | PR_FALSE); |
michael@0 | 1090 | break; |
michael@0 | 1091 | default: |
michael@0 | 1092 | /* Put this here to get rid of all those annoying warnings.*/ |
michael@0 | 1093 | break; |
michael@0 | 1094 | } |
michael@0 | 1095 | if (freeit) { |
michael@0 | 1096 | PORT_Free(inControl); |
michael@0 | 1097 | } |
michael@0 | 1098 | } |
michael@0 | 1099 | return SECSuccess; |
michael@0 | 1100 | } |
michael@0 | 1101 | |
michael@0 | 1102 | SECStatus |
michael@0 | 1103 | CRMF_DestroyControl(CRMFControl *inControl) |
michael@0 | 1104 | { |
michael@0 | 1105 | return crmf_destroy_control(inControl, PR_TRUE); |
michael@0 | 1106 | } |
michael@0 | 1107 | |
michael@0 | 1108 | static SECOidTag |
michael@0 | 1109 | crmf_controltype_to_tag(CRMFControlType inControlType) |
michael@0 | 1110 | { |
michael@0 | 1111 | SECOidTag retVal; |
michael@0 | 1112 | |
michael@0 | 1113 | switch(inControlType) { |
michael@0 | 1114 | case crmfRegTokenControl: |
michael@0 | 1115 | retVal = SEC_OID_PKIX_REGCTRL_REGTOKEN; |
michael@0 | 1116 | break; |
michael@0 | 1117 | case crmfAuthenticatorControl: |
michael@0 | 1118 | retVal = SEC_OID_PKIX_REGCTRL_AUTHENTICATOR; |
michael@0 | 1119 | break; |
michael@0 | 1120 | case crmfPKIPublicationInfoControl: |
michael@0 | 1121 | retVal = SEC_OID_PKIX_REGCTRL_PKIPUBINFO; |
michael@0 | 1122 | break; |
michael@0 | 1123 | case crmfPKIArchiveOptionsControl: |
michael@0 | 1124 | retVal = SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS; |
michael@0 | 1125 | break; |
michael@0 | 1126 | case crmfOldCertIDControl: |
michael@0 | 1127 | retVal = SEC_OID_PKIX_REGCTRL_OLD_CERT_ID; |
michael@0 | 1128 | break; |
michael@0 | 1129 | case crmfProtocolEncrKeyControl: |
michael@0 | 1130 | retVal = SEC_OID_PKIX_REGCTRL_PROTOCOL_ENC_KEY; |
michael@0 | 1131 | break; |
michael@0 | 1132 | default: |
michael@0 | 1133 | retVal = SEC_OID_UNKNOWN; |
michael@0 | 1134 | break; |
michael@0 | 1135 | } |
michael@0 | 1136 | return retVal; |
michael@0 | 1137 | } |
michael@0 | 1138 | |
michael@0 | 1139 | PRBool |
michael@0 | 1140 | CRMF_CertRequestIsControlPresent(CRMFCertRequest *inCertReq, |
michael@0 | 1141 | CRMFControlType inControlType) |
michael@0 | 1142 | { |
michael@0 | 1143 | SECOidTag controlTag; |
michael@0 | 1144 | int i; |
michael@0 | 1145 | |
michael@0 | 1146 | PORT_Assert(inCertReq != NULL); |
michael@0 | 1147 | if (inCertReq == NULL || inCertReq->controls == NULL) { |
michael@0 | 1148 | return PR_FALSE; |
michael@0 | 1149 | } |
michael@0 | 1150 | controlTag = crmf_controltype_to_tag(inControlType); |
michael@0 | 1151 | for (i=0; inCertReq->controls[i] != NULL; i++) { |
michael@0 | 1152 | if (inCertReq->controls[i]->tag == controlTag) { |
michael@0 | 1153 | return PR_TRUE; |
michael@0 | 1154 | } |
michael@0 | 1155 | } |
michael@0 | 1156 | return PR_FALSE; |
michael@0 | 1157 | } |
michael@0 | 1158 |