security/nss/lib/cryptohi/seckey.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4 #include "cryptohi.h"
michael@0 5 #include "keyhi.h"
michael@0 6 #include "secoid.h"
michael@0 7 #include "secitem.h"
michael@0 8 #include "secder.h"
michael@0 9 #include "base64.h"
michael@0 10 #include "secasn1.h"
michael@0 11 #include "cert.h"
michael@0 12 #include "pk11func.h"
michael@0 13 #include "secerr.h"
michael@0 14 #include "secdig.h"
michael@0 15 #include "prtime.h"
michael@0 16 #include "keyi.h"
michael@0 17
michael@0 18 SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
michael@0 19 SEC_ASN1_MKSUB(SEC_IntegerTemplate)
michael@0 20
michael@0 21 const SEC_ASN1Template CERT_SubjectPublicKeyInfoTemplate[] = {
michael@0 22 { SEC_ASN1_SEQUENCE,
michael@0 23 0, NULL, sizeof(CERTSubjectPublicKeyInfo) },
michael@0 24 { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
michael@0 25 offsetof(CERTSubjectPublicKeyInfo,algorithm),
michael@0 26 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
michael@0 27 { SEC_ASN1_BIT_STRING,
michael@0 28 offsetof(CERTSubjectPublicKeyInfo,subjectPublicKey), },
michael@0 29 { 0, }
michael@0 30 };
michael@0 31
michael@0 32 const SEC_ASN1Template CERT_PublicKeyAndChallengeTemplate[] =
michael@0 33 {
michael@0 34 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTPublicKeyAndChallenge) },
michael@0 35 { SEC_ASN1_ANY, offsetof(CERTPublicKeyAndChallenge,spki) },
michael@0 36 { SEC_ASN1_IA5_STRING, offsetof(CERTPublicKeyAndChallenge,challenge) },
michael@0 37 { 0 }
michael@0 38 };
michael@0 39
michael@0 40 const SEC_ASN1Template SECKEY_RSAPublicKeyTemplate[] = {
michael@0 41 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECKEYPublicKey) },
michael@0 42 { SEC_ASN1_INTEGER, offsetof(SECKEYPublicKey,u.rsa.modulus), },
michael@0 43 { SEC_ASN1_INTEGER, offsetof(SECKEYPublicKey,u.rsa.publicExponent), },
michael@0 44 { 0, }
michael@0 45 };
michael@0 46
michael@0 47 static const SEC_ASN1Template seckey_PointerToAlgorithmIDTemplate[] = {
michael@0 48 { SEC_ASN1_POINTER | SEC_ASN1_XTRN, 0,
michael@0 49 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }
michael@0 50 };
michael@0 51
michael@0 52 /* Parameters for SEC_OID_PKCS1_RSA_PSS_SIGNATURE */
michael@0 53 const SEC_ASN1Template SECKEY_RSAPSSParamsTemplate[] =
michael@0 54 {
michael@0 55 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECKEYRSAPSSParams) },
michael@0 56 { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT |
michael@0 57 SEC_ASN1_CONTEXT_SPECIFIC | 0,
michael@0 58 offsetof(SECKEYRSAPSSParams, hashAlg),
michael@0 59 seckey_PointerToAlgorithmIDTemplate },
michael@0 60 { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT |
michael@0 61 SEC_ASN1_CONTEXT_SPECIFIC | 1,
michael@0 62 offsetof(SECKEYRSAPSSParams, maskAlg),
michael@0 63 seckey_PointerToAlgorithmIDTemplate },
michael@0 64 { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT |
michael@0 65 SEC_ASN1_XTRN | SEC_ASN1_CONTEXT_SPECIFIC | 2,
michael@0 66 offsetof(SECKEYRSAPSSParams, saltLength),
michael@0 67 SEC_ASN1_SUB(SEC_IntegerTemplate) },
michael@0 68 { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT |
michael@0 69 SEC_ASN1_XTRN | SEC_ASN1_CONTEXT_SPECIFIC | 3,
michael@0 70 offsetof(SECKEYRSAPSSParams, trailerField),
michael@0 71 SEC_ASN1_SUB(SEC_IntegerTemplate) },
michael@0 72 { 0 }
michael@0 73 };
michael@0 74
michael@0 75 const SEC_ASN1Template SECKEY_DSAPublicKeyTemplate[] = {
michael@0 76 { SEC_ASN1_INTEGER, offsetof(SECKEYPublicKey,u.dsa.publicValue), },
michael@0 77 { 0, }
michael@0 78 };
michael@0 79
michael@0 80 const SEC_ASN1Template SECKEY_PQGParamsTemplate[] = {
michael@0 81 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECKEYPQGParams) },
michael@0 82 { SEC_ASN1_INTEGER, offsetof(SECKEYPQGParams,prime) },
michael@0 83 { SEC_ASN1_INTEGER, offsetof(SECKEYPQGParams,subPrime) },
michael@0 84 { SEC_ASN1_INTEGER, offsetof(SECKEYPQGParams,base) },
michael@0 85 { 0, }
michael@0 86 };
michael@0 87
michael@0 88 const SEC_ASN1Template SECKEY_DHPublicKeyTemplate[] = {
michael@0 89 { SEC_ASN1_INTEGER, offsetof(SECKEYPublicKey,u.dh.publicValue), },
michael@0 90 { 0, }
michael@0 91 };
michael@0 92
michael@0 93 const SEC_ASN1Template SECKEY_DHParamKeyTemplate[] = {
michael@0 94 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECKEYPublicKey) },
michael@0 95 { SEC_ASN1_INTEGER, offsetof(SECKEYPublicKey,u.dh.prime), },
michael@0 96 { SEC_ASN1_INTEGER, offsetof(SECKEYPublicKey,u.dh.base), },
michael@0 97 /* XXX chrisk: this needs to be expanded for decoding of j and validationParms (RFC2459 7.3.2) */
michael@0 98 { SEC_ASN1_SKIP_REST },
michael@0 99 { 0, }
michael@0 100 };
michael@0 101
michael@0 102 SEC_ASN1_CHOOSER_IMPLEMENT(SECKEY_DSAPublicKeyTemplate)
michael@0 103 SEC_ASN1_CHOOSER_IMPLEMENT(SECKEY_RSAPublicKeyTemplate)
michael@0 104 SEC_ASN1_CHOOSER_IMPLEMENT(SECKEY_RSAPSSParamsTemplate)
michael@0 105 SEC_ASN1_CHOOSER_IMPLEMENT(CERT_SubjectPublicKeyInfoTemplate)
michael@0 106
michael@0 107 /*
michael@0 108 * See bugzilla bug 125359
michael@0 109 * Since NSS (via PKCS#11) wants to handle big integers as unsigned ints,
michael@0 110 * all of the templates above that en/decode into integers must be converted
michael@0 111 * from ASN.1's signed integer type. This is done by marking either the
michael@0 112 * source or destination (encoding or decoding, respectively) type as
michael@0 113 * siUnsignedInteger.
michael@0 114 */
michael@0 115 static void
michael@0 116 prepare_rsa_pub_key_for_asn1(SECKEYPublicKey *pubk)
michael@0 117 {
michael@0 118 pubk->u.rsa.modulus.type = siUnsignedInteger;
michael@0 119 pubk->u.rsa.publicExponent.type = siUnsignedInteger;
michael@0 120 }
michael@0 121
michael@0 122 static void
michael@0 123 prepare_dsa_pub_key_for_asn1(SECKEYPublicKey *pubk)
michael@0 124 {
michael@0 125 pubk->u.dsa.publicValue.type = siUnsignedInteger;
michael@0 126 }
michael@0 127
michael@0 128 static void
michael@0 129 prepare_pqg_params_for_asn1(SECKEYPQGParams *params)
michael@0 130 {
michael@0 131 params->prime.type = siUnsignedInteger;
michael@0 132 params->subPrime.type = siUnsignedInteger;
michael@0 133 params->base.type = siUnsignedInteger;
michael@0 134 }
michael@0 135
michael@0 136 static void
michael@0 137 prepare_dh_pub_key_for_asn1(SECKEYPublicKey *pubk)
michael@0 138 {
michael@0 139 pubk->u.dh.prime.type = siUnsignedInteger;
michael@0 140 pubk->u.dh.base.type = siUnsignedInteger;
michael@0 141 pubk->u.dh.publicValue.type = siUnsignedInteger;
michael@0 142 }
michael@0 143
michael@0 144 /* Create an RSA key pair is any slot able to do so.
michael@0 145 ** The created keys are "session" (temporary), not "token" (permanent),
michael@0 146 ** and they are "sensitive", which makes them costly to move to another token.
michael@0 147 */
michael@0 148 SECKEYPrivateKey *
michael@0 149 SECKEY_CreateRSAPrivateKey(int keySizeInBits,SECKEYPublicKey **pubk, void *cx)
michael@0 150 {
michael@0 151 SECKEYPrivateKey *privk;
michael@0 152 PK11RSAGenParams param;
michael@0 153 PK11SlotInfo *slot = PK11_GetBestSlot(CKM_RSA_PKCS_KEY_PAIR_GEN,cx);
michael@0 154 if (!slot) {
michael@0 155 return NULL;
michael@0 156 }
michael@0 157
michael@0 158 param.keySizeInBits = keySizeInBits;
michael@0 159 param.pe = 65537L;
michael@0 160
michael@0 161 privk = PK11_GenerateKeyPair(slot,CKM_RSA_PKCS_KEY_PAIR_GEN,&param,pubk,
michael@0 162 PR_FALSE, PR_TRUE, cx);
michael@0 163 PK11_FreeSlot(slot);
michael@0 164 return(privk);
michael@0 165 }
michael@0 166
michael@0 167 /* Create a DH key pair in any slot able to do so,
michael@0 168 ** This is a "session" (temporary), not "token" (permanent) key.
michael@0 169 ** Because of the high probability that this key will need to be moved to
michael@0 170 ** another token, and the high cost of moving "sensitive" keys, we attempt
michael@0 171 ** to create this key pair without the "sensitive" attribute, but revert to
michael@0 172 ** creating a "sensitive" key if necessary.
michael@0 173 */
michael@0 174 SECKEYPrivateKey *
michael@0 175 SECKEY_CreateDHPrivateKey(SECKEYDHParams *param, SECKEYPublicKey **pubk, void *cx)
michael@0 176 {
michael@0 177 SECKEYPrivateKey *privk;
michael@0 178 PK11SlotInfo *slot;
michael@0 179
michael@0 180 if (!param || !param->base.data || !param->prime.data ||
michael@0 181 param->prime.len < 512/8 || param->base.len == 0 ||
michael@0 182 param->base.len > param->prime.len + 1 ||
michael@0 183 (param->base.len == 1 && param->base.data[0] == 0)) {
michael@0 184 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 185 return NULL;
michael@0 186 }
michael@0 187
michael@0 188 slot = PK11_GetBestSlot(CKM_DH_PKCS_KEY_PAIR_GEN,cx);
michael@0 189 if (!slot) {
michael@0 190 return NULL;
michael@0 191 }
michael@0 192
michael@0 193 privk = PK11_GenerateKeyPair(slot, CKM_DH_PKCS_KEY_PAIR_GEN, param,
michael@0 194 pubk, PR_FALSE, PR_FALSE, cx);
michael@0 195 if (!privk)
michael@0 196 privk = PK11_GenerateKeyPair(slot, CKM_DH_PKCS_KEY_PAIR_GEN, param,
michael@0 197 pubk, PR_FALSE, PR_TRUE, cx);
michael@0 198
michael@0 199 PK11_FreeSlot(slot);
michael@0 200 return(privk);
michael@0 201 }
michael@0 202
michael@0 203 /* Create an EC key pair in any slot able to do so,
michael@0 204 ** This is a "session" (temporary), not "token" (permanent) key.
michael@0 205 ** Because of the high probability that this key will need to be moved to
michael@0 206 ** another token, and the high cost of moving "sensitive" keys, we attempt
michael@0 207 ** to create this key pair without the "sensitive" attribute, but revert to
michael@0 208 ** creating a "sensitive" key if necessary.
michael@0 209 */
michael@0 210 SECKEYPrivateKey *
michael@0 211 SECKEY_CreateECPrivateKey(SECKEYECParams *param, SECKEYPublicKey **pubk, void *cx)
michael@0 212 {
michael@0 213 SECKEYPrivateKey *privk;
michael@0 214 PK11SlotInfo *slot = PK11_GetBestSlot(CKM_EC_KEY_PAIR_GEN,cx);
michael@0 215 if (!slot) {
michael@0 216 return NULL;
michael@0 217 }
michael@0 218
michael@0 219 privk = PK11_GenerateKeyPairWithOpFlags(slot, CKM_EC_KEY_PAIR_GEN,
michael@0 220 param, pubk,
michael@0 221 PK11_ATTR_SESSION | PK11_ATTR_INSENSITIVE |
michael@0 222 PK11_ATTR_PUBLIC,
michael@0 223 CKF_DERIVE, CKF_DERIVE|CKF_SIGN,cx);
michael@0 224 if (!privk)
michael@0 225 privk = PK11_GenerateKeyPairWithOpFlags(slot, CKM_EC_KEY_PAIR_GEN,
michael@0 226 param, pubk,
michael@0 227 PK11_ATTR_SESSION | PK11_ATTR_SENSITIVE |
michael@0 228 PK11_ATTR_PRIVATE,
michael@0 229 CKF_DERIVE, CKF_DERIVE|CKF_SIGN,cx);
michael@0 230
michael@0 231 PK11_FreeSlot(slot);
michael@0 232 return(privk);
michael@0 233 }
michael@0 234
michael@0 235 void
michael@0 236 SECKEY_DestroyPrivateKey(SECKEYPrivateKey *privk)
michael@0 237 {
michael@0 238 if (privk) {
michael@0 239 if (privk->pkcs11Slot) {
michael@0 240 if (privk->pkcs11IsTemp) {
michael@0 241 PK11_DestroyObject(privk->pkcs11Slot,privk->pkcs11ID);
michael@0 242 }
michael@0 243 PK11_FreeSlot(privk->pkcs11Slot);
michael@0 244
michael@0 245 }
michael@0 246 if (privk->arena) {
michael@0 247 PORT_FreeArena(privk->arena, PR_TRUE);
michael@0 248 }
michael@0 249 }
michael@0 250 }
michael@0 251
michael@0 252 void
michael@0 253 SECKEY_DestroyPublicKey(SECKEYPublicKey *pubk)
michael@0 254 {
michael@0 255 if (pubk) {
michael@0 256 if (pubk->pkcs11Slot) {
michael@0 257 if (!PK11_IsPermObject(pubk->pkcs11Slot,pubk->pkcs11ID)) {
michael@0 258 PK11_DestroyObject(pubk->pkcs11Slot,pubk->pkcs11ID);
michael@0 259 }
michael@0 260 PK11_FreeSlot(pubk->pkcs11Slot);
michael@0 261 }
michael@0 262 if (pubk->arena) {
michael@0 263 PORT_FreeArena(pubk->arena, PR_FALSE);
michael@0 264 }
michael@0 265 }
michael@0 266 }
michael@0 267
michael@0 268 SECStatus
michael@0 269 SECKEY_CopySubjectPublicKeyInfo(PLArenaPool *arena,
michael@0 270 CERTSubjectPublicKeyInfo *to,
michael@0 271 CERTSubjectPublicKeyInfo *from)
michael@0 272 {
michael@0 273 SECStatus rv;
michael@0 274 SECItem spk;
michael@0 275
michael@0 276 rv = SECOID_CopyAlgorithmID(arena, &to->algorithm, &from->algorithm);
michael@0 277 if (rv == SECSuccess) {
michael@0 278 /*
michael@0 279 * subjectPublicKey is a bit string, whose length is in bits.
michael@0 280 * Convert the length from bits to bytes for SECITEM_CopyItem.
michael@0 281 */
michael@0 282 spk = from->subjectPublicKey;
michael@0 283 DER_ConvertBitString(&spk);
michael@0 284 rv = SECITEM_CopyItem(arena, &to->subjectPublicKey, &spk);
michael@0 285 /* Set the length back to bits. */
michael@0 286 if (rv == SECSuccess) {
michael@0 287 to->subjectPublicKey.len = from->subjectPublicKey.len;
michael@0 288 }
michael@0 289 }
michael@0 290
michael@0 291 return rv;
michael@0 292 }
michael@0 293
michael@0 294 /* Procedure to update the pqg parameters for a cert's public key.
michael@0 295 * pqg parameters only need to be updated for DSA certificates.
michael@0 296 * The procedure uses calls to itself recursively to update a certificate
michael@0 297 * issuer's pqg parameters. Some important rules are:
michael@0 298 * - Do nothing if the cert already has PQG parameters.
michael@0 299 * - If the cert does not have PQG parameters, obtain them from the issuer.
michael@0 300 * - A valid cert chain cannot have a DSA cert without
michael@0 301 * pqg parameters that has a parent that is not a DSA cert. */
michael@0 302
michael@0 303 static SECStatus
michael@0 304 seckey_UpdateCertPQGChain(CERTCertificate * subjectCert, int count)
michael@0 305 {
michael@0 306 SECStatus rv;
michael@0 307 SECOidData *oid=NULL;
michael@0 308 int tag;
michael@0 309 CERTSubjectPublicKeyInfo * subjectSpki=NULL;
michael@0 310 CERTSubjectPublicKeyInfo * issuerSpki=NULL;
michael@0 311 CERTCertificate *issuerCert = NULL;
michael@0 312
michael@0 313 rv = SECSuccess;
michael@0 314
michael@0 315 /* increment cert chain length counter*/
michael@0 316 count++;
michael@0 317
michael@0 318 /* check if cert chain length exceeds the maximum length*/
michael@0 319 if (count > CERT_MAX_CERT_CHAIN) {
michael@0 320 return SECFailure;
michael@0 321 }
michael@0 322
michael@0 323 oid = SECOID_FindOID(&subjectCert->subjectPublicKeyInfo.algorithm.algorithm);
michael@0 324 if (oid != NULL) {
michael@0 325 tag = oid->offset;
michael@0 326
michael@0 327 /* Check if cert has a DSA or EC public key. If not, return
michael@0 328 * success since no PQG params need to be updated.
michael@0 329 *
michael@0 330 * Question: do we really need to do this for EC keys. They don't have
michael@0 331 * PQG parameters, but they do have parameters. The question is does
michael@0 332 * the child cert inherit thost parameters for EC from the parent, or
michael@0 333 * do we always include those parameters in each cert.
michael@0 334 */
michael@0 335
michael@0 336 if ( (tag != SEC_OID_ANSIX9_DSA_SIGNATURE) &&
michael@0 337 (tag != SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST) &&
michael@0 338 (tag != SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA224_DIGEST) &&
michael@0 339 (tag != SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA256_DIGEST) &&
michael@0 340 (tag != SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST) &&
michael@0 341 (tag != SEC_OID_SDN702_DSA_SIGNATURE) &&
michael@0 342 (tag != SEC_OID_ANSIX962_EC_PUBLIC_KEY) ) {
michael@0 343
michael@0 344 return SECSuccess;
michael@0 345 }
michael@0 346 } else {
michael@0 347 return SECFailure; /* return failure if oid is NULL */
michael@0 348 }
michael@0 349
michael@0 350 /* if cert has PQG parameters, return success */
michael@0 351
michael@0 352 subjectSpki=&subjectCert->subjectPublicKeyInfo;
michael@0 353
michael@0 354 if (subjectSpki->algorithm.parameters.len != 0) {
michael@0 355 return SECSuccess;
michael@0 356 }
michael@0 357
michael@0 358 /* check if the cert is self-signed */
michael@0 359 if (subjectCert->isRoot) {
michael@0 360 /* fail since cert is self-signed and has no pqg params. */
michael@0 361 return SECFailure;
michael@0 362 }
michael@0 363
michael@0 364 /* get issuer cert */
michael@0 365 issuerCert = CERT_FindCertIssuer(subjectCert, PR_Now(), certUsageAnyCA);
michael@0 366 if ( ! issuerCert ) {
michael@0 367 return SECFailure;
michael@0 368 }
michael@0 369
michael@0 370 /* if parent is not DSA, return failure since
michael@0 371 we don't allow this case. */
michael@0 372
michael@0 373 oid = SECOID_FindOID(&issuerCert->subjectPublicKeyInfo.algorithm.algorithm);
michael@0 374 if (oid != NULL) {
michael@0 375 tag = oid->offset;
michael@0 376
michael@0 377 /* Check if issuer cert has a DSA public key. If not,
michael@0 378 * return failure. */
michael@0 379
michael@0 380 if ( (tag != SEC_OID_ANSIX9_DSA_SIGNATURE) &&
michael@0 381 (tag != SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST) &&
michael@0 382 (tag != SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA224_DIGEST) &&
michael@0 383 (tag != SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA256_DIGEST) &&
michael@0 384 (tag != SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST) &&
michael@0 385 (tag != SEC_OID_SDN702_DSA_SIGNATURE) &&
michael@0 386 (tag != SEC_OID_ANSIX962_EC_PUBLIC_KEY) ) {
michael@0 387 rv = SECFailure;
michael@0 388 goto loser;
michael@0 389 }
michael@0 390 } else {
michael@0 391 rv = SECFailure; /* return failure if oid is NULL */
michael@0 392 goto loser;
michael@0 393 }
michael@0 394
michael@0 395
michael@0 396 /* at this point the subject cert has no pqg parameters and the
michael@0 397 * issuer cert has a DSA public key. Update the issuer's
michael@0 398 * pqg parameters with a recursive call to this same function. */
michael@0 399
michael@0 400 rv = seckey_UpdateCertPQGChain(issuerCert, count);
michael@0 401 if (rv != SECSuccess) {
michael@0 402 rv = SECFailure;
michael@0 403 goto loser;
michael@0 404 }
michael@0 405
michael@0 406 /* ensure issuer has pqg parameters */
michael@0 407
michael@0 408 issuerSpki=&issuerCert->subjectPublicKeyInfo;
michael@0 409 if (issuerSpki->algorithm.parameters.len == 0) {
michael@0 410 rv = SECFailure;
michael@0 411 }
michael@0 412
michael@0 413 /* if update was successful and pqg params present, then copy the
michael@0 414 * parameters to the subject cert's key. */
michael@0 415
michael@0 416 if (rv == SECSuccess) {
michael@0 417 rv = SECITEM_CopyItem(subjectCert->arena,
michael@0 418 &subjectSpki->algorithm.parameters,
michael@0 419 &issuerSpki->algorithm.parameters);
michael@0 420 }
michael@0 421
michael@0 422 loser:
michael@0 423 if (issuerCert) {
michael@0 424 CERT_DestroyCertificate(issuerCert);
michael@0 425 }
michael@0 426 return rv;
michael@0 427
michael@0 428 }
michael@0 429
michael@0 430
michael@0 431 SECStatus
michael@0 432 SECKEY_UpdateCertPQG(CERTCertificate * subjectCert)
michael@0 433 {
michael@0 434 if (!subjectCert) {
michael@0 435 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 436 return SECFailure;
michael@0 437 }
michael@0 438 return seckey_UpdateCertPQGChain(subjectCert,0);
michael@0 439 }
michael@0 440
michael@0 441
michael@0 442 /* Decode the DSA PQG parameters. The params could be stored in two
michael@0 443 * possible formats, the old fortezza-only wrapped format or
michael@0 444 * the normal standard format. Store the decoded parameters in
michael@0 445 * a V3 certificate data structure. */
michael@0 446
michael@0 447 static SECStatus
michael@0 448 seckey_DSADecodePQG(PLArenaPool *arena, SECKEYPublicKey *pubk,
michael@0 449 const SECItem *params) {
michael@0 450 SECStatus rv;
michael@0 451 SECItem newparams;
michael@0 452
michael@0 453 if (params == NULL) return SECFailure;
michael@0 454
michael@0 455 if (params->data == NULL) return SECFailure;
michael@0 456
michael@0 457 PORT_Assert(arena);
michael@0 458
michael@0 459 /* make a copy of the data into the arena so QuickDER output is valid */
michael@0 460 rv = SECITEM_CopyItem(arena, &newparams, params);
michael@0 461
michael@0 462 /* Check if params use the standard format.
michael@0 463 * The value 0xa1 will appear in the first byte of the parameter data
michael@0 464 * if the PQG parameters are not using the standard format. This
michael@0 465 * code should be changed to use a better method to detect non-standard
michael@0 466 * parameters. */
michael@0 467
michael@0 468 if ((newparams.data[0] != 0xa1) &&
michael@0 469 (newparams.data[0] != 0xa0)) {
michael@0 470
michael@0 471 if (SECSuccess == rv) {
michael@0 472 /* PQG params are in the standard format */
michael@0 473 prepare_pqg_params_for_asn1(&pubk->u.dsa.params);
michael@0 474 rv = SEC_QuickDERDecodeItem(arena, &pubk->u.dsa.params,
michael@0 475 SECKEY_PQGParamsTemplate,
michael@0 476 &newparams);
michael@0 477 }
michael@0 478 } else {
michael@0 479
michael@0 480 if (SECSuccess == rv) {
michael@0 481 /* else the old fortezza-only wrapped format is used. */
michael@0 482 PORT_SetError(SEC_ERROR_BAD_DER);
michael@0 483 rv = SECFailure;
michael@0 484 }
michael@0 485 }
michael@0 486 return rv;
michael@0 487 }
michael@0 488
michael@0 489
michael@0 490 /* Function used to make an oid tag to a key type */
michael@0 491 KeyType
michael@0 492 seckey_GetKeyType (SECOidTag tag) {
michael@0 493 KeyType keyType;
michael@0 494
michael@0 495 switch (tag) {
michael@0 496 case SEC_OID_X500_RSA_ENCRYPTION:
michael@0 497 case SEC_OID_PKCS1_RSA_ENCRYPTION:
michael@0 498 keyType = rsaKey;
michael@0 499 break;
michael@0 500 case SEC_OID_PKCS1_RSA_PSS_SIGNATURE:
michael@0 501 keyType = rsaPssKey;
michael@0 502 break;
michael@0 503 case SEC_OID_PKCS1_RSA_OAEP_ENCRYPTION:
michael@0 504 keyType = rsaOaepKey;
michael@0 505 break;
michael@0 506 case SEC_OID_ANSIX9_DSA_SIGNATURE:
michael@0 507 keyType = dsaKey;
michael@0 508 break;
michael@0 509 case SEC_OID_MISSI_KEA_DSS_OLD:
michael@0 510 case SEC_OID_MISSI_KEA_DSS:
michael@0 511 case SEC_OID_MISSI_DSS_OLD:
michael@0 512 case SEC_OID_MISSI_DSS:
michael@0 513 keyType = fortezzaKey;
michael@0 514 break;
michael@0 515 case SEC_OID_MISSI_KEA:
michael@0 516 case SEC_OID_MISSI_ALT_KEA:
michael@0 517 keyType = keaKey;
michael@0 518 break;
michael@0 519 case SEC_OID_X942_DIFFIE_HELMAN_KEY:
michael@0 520 keyType = dhKey;
michael@0 521 break;
michael@0 522 case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
michael@0 523 keyType = ecKey;
michael@0 524 break;
michael@0 525 /* accommodate applications that hand us a signature type when they
michael@0 526 * should be handing us a cipher type */
michael@0 527 case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION:
michael@0 528 case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION:
michael@0 529 case SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION:
michael@0 530 case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION:
michael@0 531 case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION:
michael@0 532 case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION:
michael@0 533 keyType = rsaKey;
michael@0 534 break;
michael@0 535 default:
michael@0 536 keyType = nullKey;
michael@0 537 }
michael@0 538 return keyType;
michael@0 539 }
michael@0 540
michael@0 541 /* Function used to determine what kind of cert we are dealing with. */
michael@0 542 KeyType
michael@0 543 CERT_GetCertKeyType (const CERTSubjectPublicKeyInfo *spki)
michael@0 544 {
michael@0 545 return seckey_GetKeyType(SECOID_GetAlgorithmTag(&spki->algorithm));
michael@0 546 }
michael@0 547
michael@0 548 static SECKEYPublicKey *
michael@0 549 seckey_ExtractPublicKey(const CERTSubjectPublicKeyInfo *spki)
michael@0 550 {
michael@0 551 SECKEYPublicKey *pubk;
michael@0 552 SECItem os, newOs, newParms;
michael@0 553 SECStatus rv;
michael@0 554 PLArenaPool *arena;
michael@0 555 SECOidTag tag;
michael@0 556
michael@0 557 arena = PORT_NewArena (DER_DEFAULT_CHUNKSIZE);
michael@0 558 if (arena == NULL)
michael@0 559 return NULL;
michael@0 560
michael@0 561 pubk = (SECKEYPublicKey *) PORT_ArenaZAlloc(arena, sizeof(SECKEYPublicKey));
michael@0 562 if (pubk == NULL) {
michael@0 563 PORT_FreeArena (arena, PR_FALSE);
michael@0 564 return NULL;
michael@0 565 }
michael@0 566
michael@0 567 pubk->arena = arena;
michael@0 568 pubk->pkcs11Slot = 0;
michael@0 569 pubk->pkcs11ID = CK_INVALID_HANDLE;
michael@0 570
michael@0 571
michael@0 572 /* Convert bit string length from bits to bytes */
michael@0 573 os = spki->subjectPublicKey;
michael@0 574 DER_ConvertBitString (&os);
michael@0 575
michael@0 576 tag = SECOID_GetAlgorithmTag(&spki->algorithm);
michael@0 577
michael@0 578 /* copy the DER into the arena, since Quick DER returns data that points
michael@0 579 into the DER input, which may get freed by the caller */
michael@0 580 rv = SECITEM_CopyItem(arena, &newOs, &os);
michael@0 581 if ( rv == SECSuccess )
michael@0 582 switch ( tag ) {
michael@0 583 case SEC_OID_X500_RSA_ENCRYPTION:
michael@0 584 case SEC_OID_PKCS1_RSA_ENCRYPTION:
michael@0 585 pubk->keyType = rsaKey;
michael@0 586 prepare_rsa_pub_key_for_asn1(pubk);
michael@0 587 rv = SEC_QuickDERDecodeItem(arena, pubk, SECKEY_RSAPublicKeyTemplate, &newOs);
michael@0 588 if (rv == SECSuccess)
michael@0 589 return pubk;
michael@0 590 break;
michael@0 591 case SEC_OID_ANSIX9_DSA_SIGNATURE:
michael@0 592 case SEC_OID_SDN702_DSA_SIGNATURE:
michael@0 593 pubk->keyType = dsaKey;
michael@0 594 prepare_dsa_pub_key_for_asn1(pubk);
michael@0 595 rv = SEC_QuickDERDecodeItem(arena, pubk, SECKEY_DSAPublicKeyTemplate, &newOs);
michael@0 596 if (rv != SECSuccess) break;
michael@0 597
michael@0 598 rv = seckey_DSADecodePQG(arena, pubk,
michael@0 599 &spki->algorithm.parameters);
michael@0 600
michael@0 601 if (rv == SECSuccess) return pubk;
michael@0 602 break;
michael@0 603 case SEC_OID_X942_DIFFIE_HELMAN_KEY:
michael@0 604 pubk->keyType = dhKey;
michael@0 605 prepare_dh_pub_key_for_asn1(pubk);
michael@0 606 rv = SEC_QuickDERDecodeItem(arena, pubk, SECKEY_DHPublicKeyTemplate, &newOs);
michael@0 607 if (rv != SECSuccess) break;
michael@0 608
michael@0 609 /* copy the DER into the arena, since Quick DER returns data that points
michael@0 610 into the DER input, which may get freed by the caller */
michael@0 611 rv = SECITEM_CopyItem(arena, &newParms, &spki->algorithm.parameters);
michael@0 612 if ( rv != SECSuccess )
michael@0 613 break;
michael@0 614
michael@0 615 rv = SEC_QuickDERDecodeItem(arena, pubk, SECKEY_DHParamKeyTemplate,
michael@0 616 &newParms);
michael@0 617
michael@0 618 if (rv == SECSuccess) return pubk;
michael@0 619 break;
michael@0 620 case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
michael@0 621 pubk->keyType = ecKey;
michael@0 622 pubk->u.ec.size = 0;
michael@0 623
michael@0 624 /* Since PKCS#11 directly takes the DER encoding of EC params
michael@0 625 * and public value, we don't need any decoding here.
michael@0 626 */
michael@0 627 rv = SECITEM_CopyItem(arena, &pubk->u.ec.DEREncodedParams,
michael@0 628 &spki->algorithm.parameters);
michael@0 629 if ( rv != SECSuccess )
michael@0 630 break;
michael@0 631 rv = SECITEM_CopyItem(arena, &pubk->u.ec.publicValue, &newOs);
michael@0 632 if (rv == SECSuccess) return pubk;
michael@0 633 break;
michael@0 634
michael@0 635 default:
michael@0 636 PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
michael@0 637 rv = SECFailure;
michael@0 638 break;
michael@0 639 }
michael@0 640
michael@0 641 SECKEY_DestroyPublicKey (pubk);
michael@0 642 return NULL;
michael@0 643 }
michael@0 644
michael@0 645
michael@0 646 /* required for JSS */
michael@0 647 SECKEYPublicKey *
michael@0 648 SECKEY_ExtractPublicKey(const CERTSubjectPublicKeyInfo *spki)
michael@0 649 {
michael@0 650 return seckey_ExtractPublicKey(spki);
michael@0 651 }
michael@0 652
michael@0 653 SECKEYPublicKey *
michael@0 654 CERT_ExtractPublicKey(CERTCertificate *cert)
michael@0 655 {
michael@0 656 SECStatus rv;
michael@0 657
michael@0 658 if (!cert) {
michael@0 659 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 660 return NULL;
michael@0 661 }
michael@0 662 rv = SECKEY_UpdateCertPQG(cert);
michael@0 663 if (rv != SECSuccess) return NULL;
michael@0 664
michael@0 665 return seckey_ExtractPublicKey(&cert->subjectPublicKeyInfo);
michael@0 666 }
michael@0 667
michael@0 668 int
michael@0 669 SECKEY_ECParamsToKeySize(const SECItem *encodedParams)
michael@0 670 {
michael@0 671 SECOidTag tag;
michael@0 672 SECItem oid = { siBuffer, NULL, 0};
michael@0 673
michael@0 674 /* The encodedParams data contains 0x06 (SEC_ASN1_OBJECT_ID),
michael@0 675 * followed by the length of the curve oid and the curve oid.
michael@0 676 */
michael@0 677 oid.len = encodedParams->data[1];
michael@0 678 oid.data = encodedParams->data + 2;
michael@0 679 if ((tag = SECOID_FindOIDTag(&oid)) == SEC_OID_UNKNOWN)
michael@0 680 return 0;
michael@0 681
michael@0 682 switch (tag) {
michael@0 683 case SEC_OID_SECG_EC_SECP112R1:
michael@0 684 case SEC_OID_SECG_EC_SECP112R2:
michael@0 685 return 112;
michael@0 686
michael@0 687 case SEC_OID_SECG_EC_SECT113R1:
michael@0 688 case SEC_OID_SECG_EC_SECT113R2:
michael@0 689 return 113;
michael@0 690
michael@0 691 case SEC_OID_SECG_EC_SECP128R1:
michael@0 692 case SEC_OID_SECG_EC_SECP128R2:
michael@0 693 return 128;
michael@0 694
michael@0 695 case SEC_OID_SECG_EC_SECT131R1:
michael@0 696 case SEC_OID_SECG_EC_SECT131R2:
michael@0 697 return 131;
michael@0 698
michael@0 699 case SEC_OID_SECG_EC_SECP160K1:
michael@0 700 case SEC_OID_SECG_EC_SECP160R1:
michael@0 701 case SEC_OID_SECG_EC_SECP160R2:
michael@0 702 return 160;
michael@0 703
michael@0 704 case SEC_OID_SECG_EC_SECT163K1:
michael@0 705 case SEC_OID_SECG_EC_SECT163R1:
michael@0 706 case SEC_OID_SECG_EC_SECT163R2:
michael@0 707 case SEC_OID_ANSIX962_EC_C2PNB163V1:
michael@0 708 case SEC_OID_ANSIX962_EC_C2PNB163V2:
michael@0 709 case SEC_OID_ANSIX962_EC_C2PNB163V3:
michael@0 710 return 163;
michael@0 711
michael@0 712 case SEC_OID_ANSIX962_EC_C2PNB176V1:
michael@0 713 return 176;
michael@0 714
michael@0 715 case SEC_OID_ANSIX962_EC_C2TNB191V1:
michael@0 716 case SEC_OID_ANSIX962_EC_C2TNB191V2:
michael@0 717 case SEC_OID_ANSIX962_EC_C2TNB191V3:
michael@0 718 case SEC_OID_ANSIX962_EC_C2ONB191V4:
michael@0 719 case SEC_OID_ANSIX962_EC_C2ONB191V5:
michael@0 720 return 191;
michael@0 721
michael@0 722 case SEC_OID_SECG_EC_SECP192K1:
michael@0 723 case SEC_OID_ANSIX962_EC_PRIME192V1:
michael@0 724 case SEC_OID_ANSIX962_EC_PRIME192V2:
michael@0 725 case SEC_OID_ANSIX962_EC_PRIME192V3:
michael@0 726 return 192;
michael@0 727
michael@0 728 case SEC_OID_SECG_EC_SECT193R1:
michael@0 729 case SEC_OID_SECG_EC_SECT193R2:
michael@0 730 return 193;
michael@0 731
michael@0 732 case SEC_OID_ANSIX962_EC_C2PNB208W1:
michael@0 733 return 208;
michael@0 734
michael@0 735 case SEC_OID_SECG_EC_SECP224K1:
michael@0 736 case SEC_OID_SECG_EC_SECP224R1:
michael@0 737 return 224;
michael@0 738
michael@0 739 case SEC_OID_SECG_EC_SECT233K1:
michael@0 740 case SEC_OID_SECG_EC_SECT233R1:
michael@0 741 return 233;
michael@0 742
michael@0 743 case SEC_OID_SECG_EC_SECT239K1:
michael@0 744 case SEC_OID_ANSIX962_EC_C2TNB239V1:
michael@0 745 case SEC_OID_ANSIX962_EC_C2TNB239V2:
michael@0 746 case SEC_OID_ANSIX962_EC_C2TNB239V3:
michael@0 747 case SEC_OID_ANSIX962_EC_C2ONB239V4:
michael@0 748 case SEC_OID_ANSIX962_EC_C2ONB239V5:
michael@0 749 case SEC_OID_ANSIX962_EC_PRIME239V1:
michael@0 750 case SEC_OID_ANSIX962_EC_PRIME239V2:
michael@0 751 case SEC_OID_ANSIX962_EC_PRIME239V3:
michael@0 752 return 239;
michael@0 753
michael@0 754 case SEC_OID_SECG_EC_SECP256K1:
michael@0 755 case SEC_OID_ANSIX962_EC_PRIME256V1:
michael@0 756 return 256;
michael@0 757
michael@0 758 case SEC_OID_ANSIX962_EC_C2PNB272W1:
michael@0 759 return 272;
michael@0 760
michael@0 761 case SEC_OID_SECG_EC_SECT283K1:
michael@0 762 case SEC_OID_SECG_EC_SECT283R1:
michael@0 763 return 283;
michael@0 764
michael@0 765 case SEC_OID_ANSIX962_EC_C2PNB304W1:
michael@0 766 return 304;
michael@0 767
michael@0 768 case SEC_OID_ANSIX962_EC_C2TNB359V1:
michael@0 769 return 359;
michael@0 770
michael@0 771 case SEC_OID_ANSIX962_EC_C2PNB368W1:
michael@0 772 return 368;
michael@0 773
michael@0 774 case SEC_OID_SECG_EC_SECP384R1:
michael@0 775 return 384;
michael@0 776
michael@0 777 case SEC_OID_SECG_EC_SECT409K1:
michael@0 778 case SEC_OID_SECG_EC_SECT409R1:
michael@0 779 return 409;
michael@0 780
michael@0 781 case SEC_OID_ANSIX962_EC_C2TNB431R1:
michael@0 782 return 431;
michael@0 783
michael@0 784 case SEC_OID_SECG_EC_SECP521R1:
michael@0 785 return 521;
michael@0 786
michael@0 787 case SEC_OID_SECG_EC_SECT571K1:
michael@0 788 case SEC_OID_SECG_EC_SECT571R1:
michael@0 789 return 571;
michael@0 790
michael@0 791 default:
michael@0 792 PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
michael@0 793 return 0;
michael@0 794 }
michael@0 795 }
michael@0 796
michael@0 797 int
michael@0 798 SECKEY_ECParamsToBasePointOrderLen(const SECItem *encodedParams)
michael@0 799 {
michael@0 800 SECOidTag tag;
michael@0 801 SECItem oid = { siBuffer, NULL, 0};
michael@0 802
michael@0 803 /* The encodedParams data contains 0x06 (SEC_ASN1_OBJECT_ID),
michael@0 804 * followed by the length of the curve oid and the curve oid.
michael@0 805 */
michael@0 806 oid.len = encodedParams->data[1];
michael@0 807 oid.data = encodedParams->data + 2;
michael@0 808 if ((tag = SECOID_FindOIDTag(&oid)) == SEC_OID_UNKNOWN)
michael@0 809 return 0;
michael@0 810
michael@0 811 switch (tag) {
michael@0 812 case SEC_OID_SECG_EC_SECP112R1:
michael@0 813 return 112;
michael@0 814 case SEC_OID_SECG_EC_SECP112R2:
michael@0 815 return 110;
michael@0 816
michael@0 817 case SEC_OID_SECG_EC_SECT113R1:
michael@0 818 case SEC_OID_SECG_EC_SECT113R2:
michael@0 819 return 113;
michael@0 820
michael@0 821 case SEC_OID_SECG_EC_SECP128R1:
michael@0 822 return 128;
michael@0 823 case SEC_OID_SECG_EC_SECP128R2:
michael@0 824 return 126;
michael@0 825
michael@0 826 case SEC_OID_SECG_EC_SECT131R1:
michael@0 827 case SEC_OID_SECG_EC_SECT131R2:
michael@0 828 return 131;
michael@0 829
michael@0 830 case SEC_OID_SECG_EC_SECP160K1:
michael@0 831 case SEC_OID_SECG_EC_SECP160R1:
michael@0 832 case SEC_OID_SECG_EC_SECP160R2:
michael@0 833 return 161;
michael@0 834
michael@0 835 case SEC_OID_SECG_EC_SECT163K1:
michael@0 836 return 163;
michael@0 837 case SEC_OID_SECG_EC_SECT163R1:
michael@0 838 return 162;
michael@0 839 case SEC_OID_SECG_EC_SECT163R2:
michael@0 840 case SEC_OID_ANSIX962_EC_C2PNB163V1:
michael@0 841 return 163;
michael@0 842 case SEC_OID_ANSIX962_EC_C2PNB163V2:
michael@0 843 case SEC_OID_ANSIX962_EC_C2PNB163V3:
michael@0 844 return 162;
michael@0 845
michael@0 846 case SEC_OID_ANSIX962_EC_C2PNB176V1:
michael@0 847 return 161;
michael@0 848
michael@0 849 case SEC_OID_ANSIX962_EC_C2TNB191V1:
michael@0 850 return 191;
michael@0 851 case SEC_OID_ANSIX962_EC_C2TNB191V2:
michael@0 852 return 190;
michael@0 853 case SEC_OID_ANSIX962_EC_C2TNB191V3:
michael@0 854 return 189;
michael@0 855 case SEC_OID_ANSIX962_EC_C2ONB191V4:
michael@0 856 return 191;
michael@0 857 case SEC_OID_ANSIX962_EC_C2ONB191V5:
michael@0 858 return 188;
michael@0 859
michael@0 860 case SEC_OID_SECG_EC_SECP192K1:
michael@0 861 case SEC_OID_ANSIX962_EC_PRIME192V1:
michael@0 862 case SEC_OID_ANSIX962_EC_PRIME192V2:
michael@0 863 case SEC_OID_ANSIX962_EC_PRIME192V3:
michael@0 864 return 192;
michael@0 865
michael@0 866 case SEC_OID_SECG_EC_SECT193R1:
michael@0 867 case SEC_OID_SECG_EC_SECT193R2:
michael@0 868 return 193;
michael@0 869
michael@0 870 case SEC_OID_ANSIX962_EC_C2PNB208W1:
michael@0 871 return 193;
michael@0 872
michael@0 873 case SEC_OID_SECG_EC_SECP224K1:
michael@0 874 return 225;
michael@0 875 case SEC_OID_SECG_EC_SECP224R1:
michael@0 876 return 224;
michael@0 877
michael@0 878 case SEC_OID_SECG_EC_SECT233K1:
michael@0 879 return 232;
michael@0 880 case SEC_OID_SECG_EC_SECT233R1:
michael@0 881 return 233;
michael@0 882
michael@0 883 case SEC_OID_SECG_EC_SECT239K1:
michael@0 884 case SEC_OID_ANSIX962_EC_C2TNB239V1:
michael@0 885 return 238;
michael@0 886 case SEC_OID_ANSIX962_EC_C2TNB239V2:
michael@0 887 return 237;
michael@0 888 case SEC_OID_ANSIX962_EC_C2TNB239V3:
michael@0 889 return 236;
michael@0 890 case SEC_OID_ANSIX962_EC_C2ONB239V4:
michael@0 891 return 238;
michael@0 892 case SEC_OID_ANSIX962_EC_C2ONB239V5:
michael@0 893 return 237;
michael@0 894 case SEC_OID_ANSIX962_EC_PRIME239V1:
michael@0 895 case SEC_OID_ANSIX962_EC_PRIME239V2:
michael@0 896 case SEC_OID_ANSIX962_EC_PRIME239V3:
michael@0 897 return 239;
michael@0 898
michael@0 899 case SEC_OID_SECG_EC_SECP256K1:
michael@0 900 case SEC_OID_ANSIX962_EC_PRIME256V1:
michael@0 901 return 256;
michael@0 902
michael@0 903 case SEC_OID_ANSIX962_EC_C2PNB272W1:
michael@0 904 return 257;
michael@0 905
michael@0 906 case SEC_OID_SECG_EC_SECT283K1:
michael@0 907 return 281;
michael@0 908 case SEC_OID_SECG_EC_SECT283R1:
michael@0 909 return 282;
michael@0 910
michael@0 911 case SEC_OID_ANSIX962_EC_C2PNB304W1:
michael@0 912 return 289;
michael@0 913
michael@0 914 case SEC_OID_ANSIX962_EC_C2TNB359V1:
michael@0 915 return 353;
michael@0 916
michael@0 917 case SEC_OID_ANSIX962_EC_C2PNB368W1:
michael@0 918 return 353;
michael@0 919
michael@0 920 case SEC_OID_SECG_EC_SECP384R1:
michael@0 921 return 384;
michael@0 922
michael@0 923 case SEC_OID_SECG_EC_SECT409K1:
michael@0 924 return 407;
michael@0 925 case SEC_OID_SECG_EC_SECT409R1:
michael@0 926 return 409;
michael@0 927
michael@0 928 case SEC_OID_ANSIX962_EC_C2TNB431R1:
michael@0 929 return 418;
michael@0 930
michael@0 931 case SEC_OID_SECG_EC_SECP521R1:
michael@0 932 return 521;
michael@0 933
michael@0 934 case SEC_OID_SECG_EC_SECT571K1:
michael@0 935 case SEC_OID_SECG_EC_SECT571R1:
michael@0 936 return 570;
michael@0 937
michael@0 938 default:
michael@0 939 PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
michael@0 940 return 0;
michael@0 941 }
michael@0 942 }
michael@0 943
michael@0 944 /* returns key strength in bytes (not bits) */
michael@0 945 unsigned
michael@0 946 SECKEY_PublicKeyStrength(const SECKEYPublicKey *pubk)
michael@0 947 {
michael@0 948 unsigned char b0;
michael@0 949 unsigned size;
michael@0 950
michael@0 951 /* interpret modulus length as key strength */
michael@0 952 if (!pubk)
michael@0 953 goto loser;
michael@0 954 switch (pubk->keyType) {
michael@0 955 case rsaKey:
michael@0 956 if (!pubk->u.rsa.modulus.data) break;
michael@0 957 b0 = pubk->u.rsa.modulus.data[0];
michael@0 958 return b0 ? pubk->u.rsa.modulus.len : pubk->u.rsa.modulus.len - 1;
michael@0 959 case dsaKey:
michael@0 960 if (!pubk->u.dsa.publicValue.data) break;
michael@0 961 b0 = pubk->u.dsa.publicValue.data[0];
michael@0 962 return b0 ? pubk->u.dsa.publicValue.len :
michael@0 963 pubk->u.dsa.publicValue.len - 1;
michael@0 964 case dhKey:
michael@0 965 if (!pubk->u.dh.publicValue.data) break;
michael@0 966 b0 = pubk->u.dh.publicValue.data[0];
michael@0 967 return b0 ? pubk->u.dh.publicValue.len :
michael@0 968 pubk->u.dh.publicValue.len - 1;
michael@0 969 case ecKey:
michael@0 970 /* Get the key size in bits and adjust */
michael@0 971 size = SECKEY_ECParamsToKeySize(&pubk->u.ec.DEREncodedParams);
michael@0 972 return (size + 7)/8;
michael@0 973 default:
michael@0 974 break;
michael@0 975 }
michael@0 976 loser:
michael@0 977 PORT_SetError(SEC_ERROR_INVALID_KEY);
michael@0 978 return 0;
michael@0 979 }
michael@0 980
michael@0 981 /* returns key strength in bits */
michael@0 982 unsigned
michael@0 983 SECKEY_PublicKeyStrengthInBits(const SECKEYPublicKey *pubk)
michael@0 984 {
michael@0 985 unsigned size;
michael@0 986 switch (pubk->keyType) {
michael@0 987 case rsaKey:
michael@0 988 case dsaKey:
michael@0 989 case dhKey:
michael@0 990 return SECKEY_PublicKeyStrength(pubk) * 8; /* 1 byte = 8 bits */
michael@0 991 case ecKey:
michael@0 992 size = SECKEY_ECParamsToKeySize(&pubk->u.ec.DEREncodedParams);
michael@0 993 return size;
michael@0 994 default:
michael@0 995 break;
michael@0 996 }
michael@0 997 PORT_SetError(SEC_ERROR_INVALID_KEY);
michael@0 998 return 0;
michael@0 999 }
michael@0 1000
michael@0 1001 /* returns signature length in bytes (not bits) */
michael@0 1002 unsigned
michael@0 1003 SECKEY_SignatureLen(const SECKEYPublicKey *pubk)
michael@0 1004 {
michael@0 1005 unsigned char b0;
michael@0 1006 unsigned size;
michael@0 1007
michael@0 1008 switch (pubk->keyType) {
michael@0 1009 case rsaKey:
michael@0 1010 b0 = pubk->u.rsa.modulus.data[0];
michael@0 1011 return b0 ? pubk->u.rsa.modulus.len : pubk->u.rsa.modulus.len - 1;
michael@0 1012 case dsaKey:
michael@0 1013 return pubk->u.dsa.params.subPrime.len * 2;
michael@0 1014 case ecKey:
michael@0 1015 /* Get the base point order length in bits and adjust */
michael@0 1016 size = SECKEY_ECParamsToBasePointOrderLen(
michael@0 1017 &pubk->u.ec.DEREncodedParams);
michael@0 1018 return ((size + 7)/8) * 2;
michael@0 1019 default:
michael@0 1020 break;
michael@0 1021 }
michael@0 1022 PORT_SetError(SEC_ERROR_INVALID_KEY);
michael@0 1023 return 0;
michael@0 1024 }
michael@0 1025
michael@0 1026 SECKEYPrivateKey *
michael@0 1027 SECKEY_CopyPrivateKey(const SECKEYPrivateKey *privk)
michael@0 1028 {
michael@0 1029 SECKEYPrivateKey *copyk;
michael@0 1030 PLArenaPool *arena;
michael@0 1031
michael@0 1032 if (!privk || !privk->pkcs11Slot) {
michael@0 1033 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 1034 return NULL;
michael@0 1035 }
michael@0 1036
michael@0 1037 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
michael@0 1038 if (arena == NULL) {
michael@0 1039 return NULL;
michael@0 1040 }
michael@0 1041
michael@0 1042 copyk = (SECKEYPrivateKey *) PORT_ArenaZAlloc (arena, sizeof (SECKEYPrivateKey));
michael@0 1043 if (copyk) {
michael@0 1044 copyk->arena = arena;
michael@0 1045 copyk->keyType = privk->keyType;
michael@0 1046
michael@0 1047 /* copy the PKCS #11 parameters */
michael@0 1048 copyk->pkcs11Slot = PK11_ReferenceSlot(privk->pkcs11Slot);
michael@0 1049 /* if the key we're referencing was a temparary key we have just
michael@0 1050 * created, that we want to go away when we're through, we need
michael@0 1051 * to make a copy of it */
michael@0 1052 if (privk->pkcs11IsTemp) {
michael@0 1053 copyk->pkcs11ID =
michael@0 1054 PK11_CopyKey(privk->pkcs11Slot,privk->pkcs11ID);
michael@0 1055 if (copyk->pkcs11ID == CK_INVALID_HANDLE) goto fail;
michael@0 1056 } else {
michael@0 1057 copyk->pkcs11ID = privk->pkcs11ID;
michael@0 1058 }
michael@0 1059 copyk->pkcs11IsTemp = privk->pkcs11IsTemp;
michael@0 1060 copyk->wincx = privk->wincx;
michael@0 1061 copyk->staticflags = privk->staticflags;
michael@0 1062 return copyk;
michael@0 1063 } else {
michael@0 1064 PORT_SetError (SEC_ERROR_NO_MEMORY);
michael@0 1065 }
michael@0 1066
michael@0 1067 fail:
michael@0 1068 PORT_FreeArena (arena, PR_FALSE);
michael@0 1069 return NULL;
michael@0 1070 }
michael@0 1071
michael@0 1072 SECKEYPublicKey *
michael@0 1073 SECKEY_CopyPublicKey(const SECKEYPublicKey *pubk)
michael@0 1074 {
michael@0 1075 SECKEYPublicKey *copyk;
michael@0 1076 PLArenaPool *arena;
michael@0 1077 SECStatus rv = SECSuccess;
michael@0 1078
michael@0 1079 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
michael@0 1080 if (arena == NULL) {
michael@0 1081 PORT_SetError (SEC_ERROR_NO_MEMORY);
michael@0 1082 return NULL;
michael@0 1083 }
michael@0 1084
michael@0 1085 copyk = (SECKEYPublicKey *) PORT_ArenaZAlloc (arena, sizeof (SECKEYPublicKey));
michael@0 1086 if (!copyk) {
michael@0 1087 PORT_FreeArena (arena, PR_FALSE);
michael@0 1088 PORT_SetError (SEC_ERROR_NO_MEMORY);
michael@0 1089 return NULL;
michael@0 1090 }
michael@0 1091
michael@0 1092 copyk->arena = arena;
michael@0 1093 copyk->keyType = pubk->keyType;
michael@0 1094 if (pubk->pkcs11Slot &&
michael@0 1095 PK11_IsPermObject(pubk->pkcs11Slot,pubk->pkcs11ID)) {
michael@0 1096 copyk->pkcs11Slot = PK11_ReferenceSlot(pubk->pkcs11Slot);
michael@0 1097 copyk->pkcs11ID = pubk->pkcs11ID;
michael@0 1098 } else {
michael@0 1099 copyk->pkcs11Slot = NULL; /* go get own reference */
michael@0 1100 copyk->pkcs11ID = CK_INVALID_HANDLE;
michael@0 1101 }
michael@0 1102 switch (pubk->keyType) {
michael@0 1103 case rsaKey:
michael@0 1104 rv = SECITEM_CopyItem(arena, &copyk->u.rsa.modulus,
michael@0 1105 &pubk->u.rsa.modulus);
michael@0 1106 if (rv == SECSuccess) {
michael@0 1107 rv = SECITEM_CopyItem (arena, &copyk->u.rsa.publicExponent,
michael@0 1108 &pubk->u.rsa.publicExponent);
michael@0 1109 if (rv == SECSuccess)
michael@0 1110 return copyk;
michael@0 1111 }
michael@0 1112 break;
michael@0 1113 case dsaKey:
michael@0 1114 rv = SECITEM_CopyItem(arena, &copyk->u.dsa.publicValue,
michael@0 1115 &pubk->u.dsa.publicValue);
michael@0 1116 if (rv != SECSuccess) break;
michael@0 1117 rv = SECITEM_CopyItem(arena, &copyk->u.dsa.params.prime,
michael@0 1118 &pubk->u.dsa.params.prime);
michael@0 1119 if (rv != SECSuccess) break;
michael@0 1120 rv = SECITEM_CopyItem(arena, &copyk->u.dsa.params.subPrime,
michael@0 1121 &pubk->u.dsa.params.subPrime);
michael@0 1122 if (rv != SECSuccess) break;
michael@0 1123 rv = SECITEM_CopyItem(arena, &copyk->u.dsa.params.base,
michael@0 1124 &pubk->u.dsa.params.base);
michael@0 1125 break;
michael@0 1126 case dhKey:
michael@0 1127 rv = SECITEM_CopyItem(arena,&copyk->u.dh.prime,&pubk->u.dh.prime);
michael@0 1128 if (rv != SECSuccess) break;
michael@0 1129 rv = SECITEM_CopyItem(arena,&copyk->u.dh.base,&pubk->u.dh.base);
michael@0 1130 if (rv != SECSuccess) break;
michael@0 1131 rv = SECITEM_CopyItem(arena, &copyk->u.dh.publicValue,
michael@0 1132 &pubk->u.dh.publicValue);
michael@0 1133 break;
michael@0 1134 case ecKey:
michael@0 1135 copyk->u.ec.size = pubk->u.ec.size;
michael@0 1136 rv = SECITEM_CopyItem(arena,&copyk->u.ec.DEREncodedParams,
michael@0 1137 &pubk->u.ec.DEREncodedParams);
michael@0 1138 if (rv != SECSuccess) break;
michael@0 1139 rv = SECITEM_CopyItem(arena,&copyk->u.ec.publicValue,
michael@0 1140 &pubk->u.ec.publicValue);
michael@0 1141 break;
michael@0 1142 case nullKey:
michael@0 1143 return copyk;
michael@0 1144 default:
michael@0 1145 PORT_SetError(SEC_ERROR_INVALID_KEY);
michael@0 1146 rv = SECFailure;
michael@0 1147 break;
michael@0 1148 }
michael@0 1149 if (rv == SECSuccess)
michael@0 1150 return copyk;
michael@0 1151
michael@0 1152 SECKEY_DestroyPublicKey (copyk);
michael@0 1153 return NULL;
michael@0 1154 }
michael@0 1155
michael@0 1156
michael@0 1157 SECKEYPublicKey *
michael@0 1158 SECKEY_ConvertToPublicKey(SECKEYPrivateKey *privk)
michael@0 1159 {
michael@0 1160 SECKEYPublicKey *pubk;
michael@0 1161 PLArenaPool *arena;
michael@0 1162 CERTCertificate *cert;
michael@0 1163 SECStatus rv;
michael@0 1164
michael@0 1165 /*
michael@0 1166 * First try to look up the cert.
michael@0 1167 */
michael@0 1168 cert = PK11_GetCertFromPrivateKey(privk);
michael@0 1169 if (cert) {
michael@0 1170 pubk = CERT_ExtractPublicKey(cert);
michael@0 1171 CERT_DestroyCertificate(cert);
michael@0 1172 return pubk;
michael@0 1173 }
michael@0 1174
michael@0 1175 /* couldn't find the cert, build pub key by hand */
michael@0 1176 arena = PORT_NewArena (DER_DEFAULT_CHUNKSIZE);
michael@0 1177 if (arena == NULL) {
michael@0 1178 PORT_SetError (SEC_ERROR_NO_MEMORY);
michael@0 1179 return NULL;
michael@0 1180 }
michael@0 1181 pubk = (SECKEYPublicKey *)PORT_ArenaZAlloc(arena,
michael@0 1182 sizeof (SECKEYPublicKey));
michael@0 1183 if (pubk == NULL) {
michael@0 1184 PORT_FreeArena(arena,PR_FALSE);
michael@0 1185 return NULL;
michael@0 1186 }
michael@0 1187 pubk->keyType = privk->keyType;
michael@0 1188 pubk->pkcs11Slot = NULL;
michael@0 1189 pubk->pkcs11ID = CK_INVALID_HANDLE;
michael@0 1190 pubk->arena = arena;
michael@0 1191
michael@0 1192 switch(privk->keyType) {
michael@0 1193 case nullKey:
michael@0 1194 case dhKey:
michael@0 1195 case dsaKey:
michael@0 1196 /* Nothing to query, if the cert isn't there, we're done -- no way
michael@0 1197 * to get the public key */
michael@0 1198 break;
michael@0 1199 case rsaKey:
michael@0 1200 rv = PK11_ReadAttribute(privk->pkcs11Slot,privk->pkcs11ID,
michael@0 1201 CKA_MODULUS,arena,&pubk->u.rsa.modulus);
michael@0 1202 if (rv != SECSuccess) break;
michael@0 1203 rv = PK11_ReadAttribute(privk->pkcs11Slot,privk->pkcs11ID,
michael@0 1204 CKA_PUBLIC_EXPONENT,arena,&pubk->u.rsa.publicExponent);
michael@0 1205 if (rv != SECSuccess) break;
michael@0 1206 return pubk;
michael@0 1207 break;
michael@0 1208 default:
michael@0 1209 break;
michael@0 1210 }
michael@0 1211
michael@0 1212 PORT_FreeArena (arena, PR_FALSE);
michael@0 1213 return NULL;
michael@0 1214 }
michael@0 1215
michael@0 1216 static CERTSubjectPublicKeyInfo *
michael@0 1217 seckey_CreateSubjectPublicKeyInfo_helper(SECKEYPublicKey *pubk)
michael@0 1218 {
michael@0 1219 CERTSubjectPublicKeyInfo *spki;
michael@0 1220 PLArenaPool *arena;
michael@0 1221 SECItem params = { siBuffer, NULL, 0 };
michael@0 1222
michael@0 1223 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
michael@0 1224 if (arena == NULL) {
michael@0 1225 PORT_SetError(SEC_ERROR_NO_MEMORY);
michael@0 1226 return NULL;
michael@0 1227 }
michael@0 1228
michael@0 1229 spki = (CERTSubjectPublicKeyInfo *) PORT_ArenaZAlloc(arena, sizeof (*spki));
michael@0 1230 if (spki != NULL) {
michael@0 1231 SECStatus rv;
michael@0 1232 SECItem *rv_item;
michael@0 1233
michael@0 1234 spki->arena = arena;
michael@0 1235 switch(pubk->keyType) {
michael@0 1236 case rsaKey:
michael@0 1237 rv = SECOID_SetAlgorithmID(arena, &spki->algorithm,
michael@0 1238 SEC_OID_PKCS1_RSA_ENCRYPTION, 0);
michael@0 1239 if (rv == SECSuccess) {
michael@0 1240 /*
michael@0 1241 * DER encode the public key into the subjectPublicKeyInfo.
michael@0 1242 */
michael@0 1243 prepare_rsa_pub_key_for_asn1(pubk);
michael@0 1244 rv_item = SEC_ASN1EncodeItem(arena, &spki->subjectPublicKey,
michael@0 1245 pubk, SECKEY_RSAPublicKeyTemplate);
michael@0 1246 if (rv_item != NULL) {
michael@0 1247 /*
michael@0 1248 * The stored value is supposed to be a BIT_STRING,
michael@0 1249 * so convert the length.
michael@0 1250 */
michael@0 1251 spki->subjectPublicKey.len <<= 3;
michael@0 1252 /*
michael@0 1253 * We got a good one; return it.
michael@0 1254 */
michael@0 1255 return spki;
michael@0 1256 }
michael@0 1257 }
michael@0 1258 break;
michael@0 1259 case dsaKey:
michael@0 1260 /* DER encode the params. */
michael@0 1261 prepare_pqg_params_for_asn1(&pubk->u.dsa.params);
michael@0 1262 rv_item = SEC_ASN1EncodeItem(arena, &params, &pubk->u.dsa.params,
michael@0 1263 SECKEY_PQGParamsTemplate);
michael@0 1264 if (rv_item != NULL) {
michael@0 1265 rv = SECOID_SetAlgorithmID(arena, &spki->algorithm,
michael@0 1266 SEC_OID_ANSIX9_DSA_SIGNATURE,
michael@0 1267 &params);
michael@0 1268 if (rv == SECSuccess) {
michael@0 1269 /*
michael@0 1270 * DER encode the public key into the subjectPublicKeyInfo.
michael@0 1271 */
michael@0 1272 prepare_dsa_pub_key_for_asn1(pubk);
michael@0 1273 rv_item = SEC_ASN1EncodeItem(arena, &spki->subjectPublicKey,
michael@0 1274 pubk,
michael@0 1275 SECKEY_DSAPublicKeyTemplate);
michael@0 1276 if (rv_item != NULL) {
michael@0 1277 /*
michael@0 1278 * The stored value is supposed to be a BIT_STRING,
michael@0 1279 * so convert the length.
michael@0 1280 */
michael@0 1281 spki->subjectPublicKey.len <<= 3;
michael@0 1282 /*
michael@0 1283 * We got a good one; return it.
michael@0 1284 */
michael@0 1285 return spki;
michael@0 1286 }
michael@0 1287 }
michael@0 1288 }
michael@0 1289 SECITEM_FreeItem(&params, PR_FALSE);
michael@0 1290 break;
michael@0 1291 case ecKey:
michael@0 1292 rv = SECITEM_CopyItem(arena, &params,
michael@0 1293 &pubk->u.ec.DEREncodedParams);
michael@0 1294 if (rv != SECSuccess) break;
michael@0 1295
michael@0 1296 rv = SECOID_SetAlgorithmID(arena, &spki->algorithm,
michael@0 1297 SEC_OID_ANSIX962_EC_PUBLIC_KEY,
michael@0 1298 &params);
michael@0 1299 if (rv != SECSuccess) break;
michael@0 1300
michael@0 1301 rv = SECITEM_CopyItem(arena, &spki->subjectPublicKey,
michael@0 1302 &pubk->u.ec.publicValue);
michael@0 1303
michael@0 1304 if (rv == SECSuccess) {
michael@0 1305 /*
michael@0 1306 * The stored value is supposed to be a BIT_STRING,
michael@0 1307 * so convert the length.
michael@0 1308 */
michael@0 1309 spki->subjectPublicKey.len <<= 3;
michael@0 1310 /*
michael@0 1311 * We got a good one; return it.
michael@0 1312 */
michael@0 1313 return spki;
michael@0 1314 }
michael@0 1315 break;
michael@0 1316 case dhKey: /* later... */
michael@0 1317
michael@0 1318 break;
michael@0 1319 default:
michael@0 1320 break;
michael@0 1321 }
michael@0 1322 } else {
michael@0 1323 PORT_SetError(SEC_ERROR_NO_MEMORY);
michael@0 1324 }
michael@0 1325
michael@0 1326 PORT_FreeArena(arena, PR_FALSE);
michael@0 1327 return NULL;
michael@0 1328 }
michael@0 1329
michael@0 1330 CERTSubjectPublicKeyInfo *
michael@0 1331 SECKEY_CreateSubjectPublicKeyInfo(const SECKEYPublicKey *pubk)
michael@0 1332 {
michael@0 1333 CERTSubjectPublicKeyInfo *spki;
michael@0 1334 SECKEYPublicKey *tempKey;
michael@0 1335
michael@0 1336 if (!pubk) {
michael@0 1337 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 1338 return NULL;
michael@0 1339 }
michael@0 1340
michael@0 1341 tempKey = SECKEY_CopyPublicKey(pubk);
michael@0 1342 if (!tempKey) {
michael@0 1343 return NULL;
michael@0 1344 }
michael@0 1345 spki = seckey_CreateSubjectPublicKeyInfo_helper(tempKey);
michael@0 1346 SECKEY_DestroyPublicKey(tempKey);
michael@0 1347 return spki;
michael@0 1348 }
michael@0 1349
michael@0 1350 void
michael@0 1351 SECKEY_DestroySubjectPublicKeyInfo(CERTSubjectPublicKeyInfo *spki)
michael@0 1352 {
michael@0 1353 if (spki && spki->arena) {
michael@0 1354 PORT_FreeArena(spki->arena, PR_FALSE);
michael@0 1355 }
michael@0 1356 }
michael@0 1357
michael@0 1358 SECItem *
michael@0 1359 SECKEY_EncodeDERSubjectPublicKeyInfo(const SECKEYPublicKey *pubk)
michael@0 1360 {
michael@0 1361 CERTSubjectPublicKeyInfo *spki=NULL;
michael@0 1362 SECItem *spkiDER=NULL;
michael@0 1363
michael@0 1364 /* get the subjectpublickeyinfo */
michael@0 1365 spki = SECKEY_CreateSubjectPublicKeyInfo(pubk);
michael@0 1366 if( spki == NULL ) {
michael@0 1367 goto finish;
michael@0 1368 }
michael@0 1369
michael@0 1370 /* DER-encode the subjectpublickeyinfo */
michael@0 1371 spkiDER = SEC_ASN1EncodeItem(NULL /*arena*/, NULL/*dest*/, spki,
michael@0 1372 CERT_SubjectPublicKeyInfoTemplate);
michael@0 1373
michael@0 1374 SECKEY_DestroySubjectPublicKeyInfo(spki);
michael@0 1375
michael@0 1376 finish:
michael@0 1377 return spkiDER;
michael@0 1378 }
michael@0 1379
michael@0 1380
michael@0 1381 CERTSubjectPublicKeyInfo *
michael@0 1382 SECKEY_DecodeDERSubjectPublicKeyInfo(const SECItem *spkider)
michael@0 1383 {
michael@0 1384 PLArenaPool *arena;
michael@0 1385 CERTSubjectPublicKeyInfo *spki;
michael@0 1386 SECStatus rv;
michael@0 1387 SECItem newSpkider;
michael@0 1388
michael@0 1389 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
michael@0 1390 if (arena == NULL) {
michael@0 1391 PORT_SetError(SEC_ERROR_NO_MEMORY);
michael@0 1392 return NULL;
michael@0 1393 }
michael@0 1394
michael@0 1395 spki = (CERTSubjectPublicKeyInfo *)
michael@0 1396 PORT_ArenaZAlloc(arena, sizeof (CERTSubjectPublicKeyInfo));
michael@0 1397 if (spki != NULL) {
michael@0 1398 spki->arena = arena;
michael@0 1399
michael@0 1400 /* copy the DER into the arena, since Quick DER returns data that points
michael@0 1401 into the DER input, which may get freed by the caller */
michael@0 1402 rv = SECITEM_CopyItem(arena, &newSpkider, spkider);
michael@0 1403 if ( rv == SECSuccess ) {
michael@0 1404 rv = SEC_QuickDERDecodeItem(arena,spki,
michael@0 1405 CERT_SubjectPublicKeyInfoTemplate, &newSpkider);
michael@0 1406 }
michael@0 1407 if (rv == SECSuccess)
michael@0 1408 return spki;
michael@0 1409 } else {
michael@0 1410 PORT_SetError(SEC_ERROR_NO_MEMORY);
michael@0 1411 }
michael@0 1412
michael@0 1413 PORT_FreeArena(arena, PR_FALSE);
michael@0 1414 return NULL;
michael@0 1415 }
michael@0 1416
michael@0 1417 /*
michael@0 1418 * Decode a base64 ascii encoded DER encoded subject public key info.
michael@0 1419 */
michael@0 1420 CERTSubjectPublicKeyInfo *
michael@0 1421 SECKEY_ConvertAndDecodeSubjectPublicKeyInfo(const char *spkistr)
michael@0 1422 {
michael@0 1423 CERTSubjectPublicKeyInfo *spki;
michael@0 1424 SECStatus rv;
michael@0 1425 SECItem der;
michael@0 1426
michael@0 1427 rv = ATOB_ConvertAsciiToItem(&der, spkistr);
michael@0 1428 if (rv != SECSuccess)
michael@0 1429 return NULL;
michael@0 1430
michael@0 1431 spki = SECKEY_DecodeDERSubjectPublicKeyInfo(&der);
michael@0 1432
michael@0 1433 PORT_Free(der.data);
michael@0 1434 return spki;
michael@0 1435 }
michael@0 1436
michael@0 1437 /*
michael@0 1438 * Decode a base64 ascii encoded DER encoded public key and challenge
michael@0 1439 * Verify digital signature and make sure challenge matches
michael@0 1440 */
michael@0 1441 CERTSubjectPublicKeyInfo *
michael@0 1442 SECKEY_ConvertAndDecodePublicKeyAndChallenge(char *pkacstr, char *challenge,
michael@0 1443 void *wincx)
michael@0 1444 {
michael@0 1445 CERTSubjectPublicKeyInfo *spki = NULL;
michael@0 1446 CERTPublicKeyAndChallenge pkac;
michael@0 1447 SECStatus rv;
michael@0 1448 SECItem signedItem;
michael@0 1449 PLArenaPool *arena = NULL;
michael@0 1450 CERTSignedData sd;
michael@0 1451 SECItem sig;
michael@0 1452 SECKEYPublicKey *pubKey = NULL;
michael@0 1453 unsigned int len;
michael@0 1454
michael@0 1455 signedItem.data = NULL;
michael@0 1456
michael@0 1457 /* convert the base64 encoded data to binary */
michael@0 1458 rv = ATOB_ConvertAsciiToItem(&signedItem, pkacstr);
michael@0 1459 if (rv != SECSuccess) {
michael@0 1460 goto loser;
michael@0 1461 }
michael@0 1462
michael@0 1463 /* create an arena */
michael@0 1464 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
michael@0 1465 if (arena == NULL) {
michael@0 1466 goto loser;
michael@0 1467 }
michael@0 1468
michael@0 1469 /* decode the outer wrapping of signed data */
michael@0 1470 PORT_Memset(&sd, 0, sizeof(CERTSignedData));
michael@0 1471 rv = SEC_QuickDERDecodeItem(arena, &sd, CERT_SignedDataTemplate, &signedItem );
michael@0 1472 if ( rv ) {
michael@0 1473 goto loser;
michael@0 1474 }
michael@0 1475
michael@0 1476 /* decode the public key and challenge wrapper */
michael@0 1477 PORT_Memset(&pkac, 0, sizeof(CERTPublicKeyAndChallenge));
michael@0 1478 rv = SEC_QuickDERDecodeItem(arena, &pkac, CERT_PublicKeyAndChallengeTemplate,
michael@0 1479 &sd.data);
michael@0 1480 if ( rv ) {
michael@0 1481 goto loser;
michael@0 1482 }
michael@0 1483
michael@0 1484 /* decode the subject public key info */
michael@0 1485 spki = SECKEY_DecodeDERSubjectPublicKeyInfo(&pkac.spki);
michael@0 1486 if ( spki == NULL ) {
michael@0 1487 goto loser;
michael@0 1488 }
michael@0 1489
michael@0 1490 /* get the public key */
michael@0 1491 pubKey = seckey_ExtractPublicKey(spki);
michael@0 1492 if ( pubKey == NULL ) {
michael@0 1493 goto loser;
michael@0 1494 }
michael@0 1495
michael@0 1496 /* check the signature */
michael@0 1497 sig = sd.signature;
michael@0 1498 DER_ConvertBitString(&sig);
michael@0 1499 rv = VFY_VerifyDataWithAlgorithmID(sd.data.data, sd.data.len, pubKey, &sig,
michael@0 1500 &(sd.signatureAlgorithm), NULL, wincx);
michael@0 1501 if ( rv != SECSuccess ) {
michael@0 1502 goto loser;
michael@0 1503 }
michael@0 1504
michael@0 1505 /* check the challenge */
michael@0 1506 if ( challenge ) {
michael@0 1507 len = PORT_Strlen(challenge);
michael@0 1508 /* length is right */
michael@0 1509 if ( len != pkac.challenge.len ) {
michael@0 1510 goto loser;
michael@0 1511 }
michael@0 1512 /* actual data is right */
michael@0 1513 if ( PORT_Memcmp(challenge, pkac.challenge.data, len) != 0 ) {
michael@0 1514 goto loser;
michael@0 1515 }
michael@0 1516 }
michael@0 1517 goto done;
michael@0 1518
michael@0 1519 loser:
michael@0 1520 /* make sure that we return null if we got an error */
michael@0 1521 if ( spki ) {
michael@0 1522 SECKEY_DestroySubjectPublicKeyInfo(spki);
michael@0 1523 }
michael@0 1524 spki = NULL;
michael@0 1525
michael@0 1526 done:
michael@0 1527 if ( signedItem.data ) {
michael@0 1528 PORT_Free(signedItem.data);
michael@0 1529 }
michael@0 1530 if ( arena ) {
michael@0 1531 PORT_FreeArena(arena, PR_FALSE);
michael@0 1532 }
michael@0 1533 if ( pubKey ) {
michael@0 1534 SECKEY_DestroyPublicKey(pubKey);
michael@0 1535 }
michael@0 1536
michael@0 1537 return spki;
michael@0 1538 }
michael@0 1539
michael@0 1540 void
michael@0 1541 SECKEY_DestroyPrivateKeyInfo(SECKEYPrivateKeyInfo *pvk,
michael@0 1542 PRBool freeit)
michael@0 1543 {
michael@0 1544 PLArenaPool *poolp;
michael@0 1545
michael@0 1546 if(pvk != NULL) {
michael@0 1547 if(pvk->arena) {
michael@0 1548 poolp = pvk->arena;
michael@0 1549 /* zero structure since PORT_FreeArena does not support
michael@0 1550 * this yet.
michael@0 1551 */
michael@0 1552 PORT_Memset(pvk->privateKey.data, 0, pvk->privateKey.len);
michael@0 1553 PORT_Memset((char *)pvk, 0, sizeof(*pvk));
michael@0 1554 if(freeit == PR_TRUE) {
michael@0 1555 PORT_FreeArena(poolp, PR_TRUE);
michael@0 1556 } else {
michael@0 1557 pvk->arena = poolp;
michael@0 1558 }
michael@0 1559 } else {
michael@0 1560 SECITEM_ZfreeItem(&pvk->version, PR_FALSE);
michael@0 1561 SECITEM_ZfreeItem(&pvk->privateKey, PR_FALSE);
michael@0 1562 SECOID_DestroyAlgorithmID(&pvk->algorithm, PR_FALSE);
michael@0 1563 PORT_Memset((char *)pvk, 0, sizeof(*pvk));
michael@0 1564 if(freeit == PR_TRUE) {
michael@0 1565 PORT_Free(pvk);
michael@0 1566 }
michael@0 1567 }
michael@0 1568 }
michael@0 1569 }
michael@0 1570
michael@0 1571 void
michael@0 1572 SECKEY_DestroyEncryptedPrivateKeyInfo(SECKEYEncryptedPrivateKeyInfo *epki,
michael@0 1573 PRBool freeit)
michael@0 1574 {
michael@0 1575 PLArenaPool *poolp;
michael@0 1576
michael@0 1577 if(epki != NULL) {
michael@0 1578 if(epki->arena) {
michael@0 1579 poolp = epki->arena;
michael@0 1580 /* zero structure since PORT_FreeArena does not support
michael@0 1581 * this yet.
michael@0 1582 */
michael@0 1583 PORT_Memset(epki->encryptedData.data, 0, epki->encryptedData.len);
michael@0 1584 PORT_Memset((char *)epki, 0, sizeof(*epki));
michael@0 1585 if(freeit == PR_TRUE) {
michael@0 1586 PORT_FreeArena(poolp, PR_TRUE);
michael@0 1587 } else {
michael@0 1588 epki->arena = poolp;
michael@0 1589 }
michael@0 1590 } else {
michael@0 1591 SECITEM_ZfreeItem(&epki->encryptedData, PR_FALSE);
michael@0 1592 SECOID_DestroyAlgorithmID(&epki->algorithm, PR_FALSE);
michael@0 1593 PORT_Memset((char *)epki, 0, sizeof(*epki));
michael@0 1594 if(freeit == PR_TRUE) {
michael@0 1595 PORT_Free(epki);
michael@0 1596 }
michael@0 1597 }
michael@0 1598 }
michael@0 1599 }
michael@0 1600
michael@0 1601 SECStatus
michael@0 1602 SECKEY_CopyPrivateKeyInfo(PLArenaPool *poolp,
michael@0 1603 SECKEYPrivateKeyInfo *to,
michael@0 1604 const SECKEYPrivateKeyInfo *from)
michael@0 1605 {
michael@0 1606 SECStatus rv = SECFailure;
michael@0 1607
michael@0 1608 if((to == NULL) || (from == NULL)) {
michael@0 1609 return SECFailure;
michael@0 1610 }
michael@0 1611
michael@0 1612 rv = SECOID_CopyAlgorithmID(poolp, &to->algorithm, &from->algorithm);
michael@0 1613 if(rv != SECSuccess) {
michael@0 1614 return SECFailure;
michael@0 1615 }
michael@0 1616 rv = SECITEM_CopyItem(poolp, &to->privateKey, &from->privateKey);
michael@0 1617 if(rv != SECSuccess) {
michael@0 1618 return SECFailure;
michael@0 1619 }
michael@0 1620 rv = SECITEM_CopyItem(poolp, &to->version, &from->version);
michael@0 1621
michael@0 1622 return rv;
michael@0 1623 }
michael@0 1624
michael@0 1625 SECStatus
michael@0 1626 SECKEY_CopyEncryptedPrivateKeyInfo(PLArenaPool *poolp,
michael@0 1627 SECKEYEncryptedPrivateKeyInfo *to,
michael@0 1628 const SECKEYEncryptedPrivateKeyInfo *from)
michael@0 1629 {
michael@0 1630 SECStatus rv = SECFailure;
michael@0 1631
michael@0 1632 if((to == NULL) || (from == NULL)) {
michael@0 1633 return SECFailure;
michael@0 1634 }
michael@0 1635
michael@0 1636 rv = SECOID_CopyAlgorithmID(poolp, &to->algorithm, &from->algorithm);
michael@0 1637 if(rv != SECSuccess) {
michael@0 1638 return SECFailure;
michael@0 1639 }
michael@0 1640 rv = SECITEM_CopyItem(poolp, &to->encryptedData, &from->encryptedData);
michael@0 1641
michael@0 1642 return rv;
michael@0 1643 }
michael@0 1644
michael@0 1645 KeyType
michael@0 1646 SECKEY_GetPrivateKeyType(const SECKEYPrivateKey *privKey)
michael@0 1647 {
michael@0 1648 return privKey->keyType;
michael@0 1649 }
michael@0 1650
michael@0 1651 KeyType
michael@0 1652 SECKEY_GetPublicKeyType(const SECKEYPublicKey *pubKey)
michael@0 1653 {
michael@0 1654 return pubKey->keyType;
michael@0 1655 }
michael@0 1656
michael@0 1657 SECKEYPublicKey*
michael@0 1658 SECKEY_ImportDERPublicKey(const SECItem *derKey, CK_KEY_TYPE type)
michael@0 1659 {
michael@0 1660 SECKEYPublicKey *pubk = NULL;
michael@0 1661 SECStatus rv = SECFailure;
michael@0 1662 SECItem newDerKey;
michael@0 1663 PLArenaPool *arena = NULL;
michael@0 1664
michael@0 1665 if (!derKey) {
michael@0 1666 return NULL;
michael@0 1667 }
michael@0 1668
michael@0 1669 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
michael@0 1670 if (arena == NULL) {
michael@0 1671 PORT_SetError(SEC_ERROR_NO_MEMORY);
michael@0 1672 goto finish;
michael@0 1673 }
michael@0 1674
michael@0 1675 pubk = PORT_ArenaZNew(arena, SECKEYPublicKey);
michael@0 1676 if (pubk == NULL) {
michael@0 1677 goto finish;
michael@0 1678 }
michael@0 1679 pubk->arena = arena;
michael@0 1680
michael@0 1681 rv = SECITEM_CopyItem(pubk->arena, &newDerKey, derKey);
michael@0 1682 if (SECSuccess != rv) {
michael@0 1683 goto finish;
michael@0 1684 }
michael@0 1685
michael@0 1686 pubk->pkcs11Slot = NULL;
michael@0 1687 pubk->pkcs11ID = CK_INVALID_HANDLE;
michael@0 1688
michael@0 1689 switch( type ) {
michael@0 1690 case CKK_RSA:
michael@0 1691 prepare_rsa_pub_key_for_asn1(pubk);
michael@0 1692 rv = SEC_QuickDERDecodeItem(pubk->arena, pubk, SECKEY_RSAPublicKeyTemplate, &newDerKey);
michael@0 1693 pubk->keyType = rsaKey;
michael@0 1694 break;
michael@0 1695 case CKK_DSA:
michael@0 1696 prepare_dsa_pub_key_for_asn1(pubk);
michael@0 1697 rv = SEC_QuickDERDecodeItem(pubk->arena, pubk, SECKEY_DSAPublicKeyTemplate, &newDerKey);
michael@0 1698 pubk->keyType = dsaKey;
michael@0 1699 break;
michael@0 1700 case CKK_DH:
michael@0 1701 prepare_dh_pub_key_for_asn1(pubk);
michael@0 1702 rv = SEC_QuickDERDecodeItem(pubk->arena, pubk, SECKEY_DHPublicKeyTemplate, &newDerKey);
michael@0 1703 pubk->keyType = dhKey;
michael@0 1704 break;
michael@0 1705 default:
michael@0 1706 rv = SECFailure;
michael@0 1707 break;
michael@0 1708 }
michael@0 1709
michael@0 1710 finish:
michael@0 1711 if (rv != SECSuccess) {
michael@0 1712 if (arena != NULL) {
michael@0 1713 PORT_FreeArena(arena, PR_FALSE);
michael@0 1714 }
michael@0 1715 pubk = NULL;
michael@0 1716 }
michael@0 1717 return pubk;
michael@0 1718 }
michael@0 1719
michael@0 1720 SECKEYPrivateKeyList*
michael@0 1721 SECKEY_NewPrivateKeyList(void)
michael@0 1722 {
michael@0 1723 PLArenaPool *arena = NULL;
michael@0 1724 SECKEYPrivateKeyList *ret = NULL;
michael@0 1725
michael@0 1726 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
michael@0 1727 if ( arena == NULL ) {
michael@0 1728 goto loser;
michael@0 1729 }
michael@0 1730
michael@0 1731 ret = (SECKEYPrivateKeyList *)PORT_ArenaZAlloc(arena,
michael@0 1732 sizeof(SECKEYPrivateKeyList));
michael@0 1733 if ( ret == NULL ) {
michael@0 1734 goto loser;
michael@0 1735 }
michael@0 1736
michael@0 1737 ret->arena = arena;
michael@0 1738
michael@0 1739 PR_INIT_CLIST(&ret->list);
michael@0 1740
michael@0 1741 return(ret);
michael@0 1742
michael@0 1743 loser:
michael@0 1744 if ( arena != NULL ) {
michael@0 1745 PORT_FreeArena(arena, PR_FALSE);
michael@0 1746 }
michael@0 1747
michael@0 1748 return(NULL);
michael@0 1749 }
michael@0 1750
michael@0 1751 void
michael@0 1752 SECKEY_DestroyPrivateKeyList(SECKEYPrivateKeyList *keys)
michael@0 1753 {
michael@0 1754 while( !PR_CLIST_IS_EMPTY(&keys->list) ) {
michael@0 1755 SECKEY_RemovePrivateKeyListNode(
michael@0 1756 (SECKEYPrivateKeyListNode*)(PR_LIST_HEAD(&keys->list)) );
michael@0 1757 }
michael@0 1758
michael@0 1759 PORT_FreeArena(keys->arena, PR_FALSE);
michael@0 1760
michael@0 1761 return;
michael@0 1762 }
michael@0 1763
michael@0 1764
michael@0 1765 void
michael@0 1766 SECKEY_RemovePrivateKeyListNode(SECKEYPrivateKeyListNode *node)
michael@0 1767 {
michael@0 1768 PR_ASSERT(node->key);
michael@0 1769 SECKEY_DestroyPrivateKey(node->key);
michael@0 1770 node->key = NULL;
michael@0 1771 PR_REMOVE_LINK(&node->links);
michael@0 1772 return;
michael@0 1773
michael@0 1774 }
michael@0 1775
michael@0 1776 SECStatus
michael@0 1777 SECKEY_AddPrivateKeyToListTail( SECKEYPrivateKeyList *list,
michael@0 1778 SECKEYPrivateKey *key)
michael@0 1779 {
michael@0 1780 SECKEYPrivateKeyListNode *node;
michael@0 1781
michael@0 1782 node = (SECKEYPrivateKeyListNode *)PORT_ArenaZAlloc(list->arena,
michael@0 1783 sizeof(SECKEYPrivateKeyListNode));
michael@0 1784 if ( node == NULL ) {
michael@0 1785 goto loser;
michael@0 1786 }
michael@0 1787
michael@0 1788 PR_INSERT_BEFORE(&node->links, &list->list);
michael@0 1789 node->key = key;
michael@0 1790 return(SECSuccess);
michael@0 1791
michael@0 1792 loser:
michael@0 1793 return(SECFailure);
michael@0 1794 }
michael@0 1795
michael@0 1796
michael@0 1797 SECKEYPublicKeyList*
michael@0 1798 SECKEY_NewPublicKeyList(void)
michael@0 1799 {
michael@0 1800 PLArenaPool *arena = NULL;
michael@0 1801 SECKEYPublicKeyList *ret = NULL;
michael@0 1802
michael@0 1803 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
michael@0 1804 if ( arena == NULL ) {
michael@0 1805 goto loser;
michael@0 1806 }
michael@0 1807
michael@0 1808 ret = (SECKEYPublicKeyList *)PORT_ArenaZAlloc(arena,
michael@0 1809 sizeof(SECKEYPublicKeyList));
michael@0 1810 if ( ret == NULL ) {
michael@0 1811 goto loser;
michael@0 1812 }
michael@0 1813
michael@0 1814 ret->arena = arena;
michael@0 1815
michael@0 1816 PR_INIT_CLIST(&ret->list);
michael@0 1817
michael@0 1818 return(ret);
michael@0 1819
michael@0 1820 loser:
michael@0 1821 if ( arena != NULL ) {
michael@0 1822 PORT_FreeArena(arena, PR_FALSE);
michael@0 1823 }
michael@0 1824
michael@0 1825 return(NULL);
michael@0 1826 }
michael@0 1827
michael@0 1828 void
michael@0 1829 SECKEY_DestroyPublicKeyList(SECKEYPublicKeyList *keys)
michael@0 1830 {
michael@0 1831 while( !PR_CLIST_IS_EMPTY(&keys->list) ) {
michael@0 1832 SECKEY_RemovePublicKeyListNode(
michael@0 1833 (SECKEYPublicKeyListNode*)(PR_LIST_HEAD(&keys->list)) );
michael@0 1834 }
michael@0 1835
michael@0 1836 PORT_FreeArena(keys->arena, PR_FALSE);
michael@0 1837
michael@0 1838 return;
michael@0 1839 }
michael@0 1840
michael@0 1841
michael@0 1842 void
michael@0 1843 SECKEY_RemovePublicKeyListNode(SECKEYPublicKeyListNode *node)
michael@0 1844 {
michael@0 1845 PR_ASSERT(node->key);
michael@0 1846 SECKEY_DestroyPublicKey(node->key);
michael@0 1847 node->key = NULL;
michael@0 1848 PR_REMOVE_LINK(&node->links);
michael@0 1849 return;
michael@0 1850
michael@0 1851 }
michael@0 1852
michael@0 1853 SECStatus
michael@0 1854 SECKEY_AddPublicKeyToListTail( SECKEYPublicKeyList *list,
michael@0 1855 SECKEYPublicKey *key)
michael@0 1856 {
michael@0 1857 SECKEYPublicKeyListNode *node;
michael@0 1858
michael@0 1859 node = (SECKEYPublicKeyListNode *)PORT_ArenaZAlloc(list->arena,
michael@0 1860 sizeof(SECKEYPublicKeyListNode));
michael@0 1861 if ( node == NULL ) {
michael@0 1862 goto loser;
michael@0 1863 }
michael@0 1864
michael@0 1865 PR_INSERT_BEFORE(&node->links, &list->list);
michael@0 1866 node->key = key;
michael@0 1867 return(SECSuccess);
michael@0 1868
michael@0 1869 loser:
michael@0 1870 return(SECFailure);
michael@0 1871 }
michael@0 1872
michael@0 1873 #define SECKEY_CacheAttribute(key, attribute) \
michael@0 1874 if (CK_TRUE == PK11_HasAttributeSet(key->pkcs11Slot, key->pkcs11ID, attribute, PR_FALSE)) { \
michael@0 1875 key->staticflags |= SECKEY_##attribute; \
michael@0 1876 } else { \
michael@0 1877 key->staticflags &= (~SECKEY_##attribute); \
michael@0 1878 }
michael@0 1879
michael@0 1880 SECStatus
michael@0 1881 SECKEY_CacheStaticFlags(SECKEYPrivateKey* key)
michael@0 1882 {
michael@0 1883 SECStatus rv = SECFailure;
michael@0 1884 if (key && key->pkcs11Slot && key->pkcs11ID) {
michael@0 1885 key->staticflags |= SECKEY_Attributes_Cached;
michael@0 1886 SECKEY_CacheAttribute(key, CKA_PRIVATE);
michael@0 1887 SECKEY_CacheAttribute(key, CKA_ALWAYS_AUTHENTICATE);
michael@0 1888 rv = SECSuccess;
michael@0 1889 }
michael@0 1890 return rv;
michael@0 1891 }

mercurial