1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/cryptohi/secsign.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,496 @@ 1.4 +/* 1.5 + * Signature stuff. 1.6 + * 1.7 + * This Source Code Form is subject to the terms of the Mozilla Public 1.8 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.9 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.10 + 1.11 +#include <stdio.h> 1.12 +#include "cryptohi.h" 1.13 +#include "sechash.h" 1.14 +#include "secder.h" 1.15 +#include "keyhi.h" 1.16 +#include "secoid.h" 1.17 +#include "secdig.h" 1.18 +#include "pk11func.h" 1.19 +#include "secerr.h" 1.20 +#include "keyi.h" 1.21 + 1.22 +struct SGNContextStr { 1.23 + SECOidTag signalg; 1.24 + SECOidTag hashalg; 1.25 + void *hashcx; 1.26 + const SECHashObject *hashobj; 1.27 + SECKEYPrivateKey *key; 1.28 +}; 1.29 + 1.30 +SGNContext * 1.31 +SGN_NewContext(SECOidTag alg, SECKEYPrivateKey *key) 1.32 +{ 1.33 + SGNContext *cx; 1.34 + SECOidTag hashalg, signalg; 1.35 + KeyType keyType; 1.36 + SECStatus rv; 1.37 + 1.38 + /* OK, map a PKCS #7 hash and encrypt algorithm into 1.39 + * a standard hashing algorithm. Why did we pass in the whole 1.40 + * PKCS #7 algTag if we were just going to change here you might 1.41 + * ask. Well the answer is for some cards we may have to do the 1.42 + * hashing on card. It may not support CKM_RSA_PKCS sign algorithm, 1.43 + * it may just support CKM_SHA1_RSA_PKCS and/or CKM_MD5_RSA_PKCS. 1.44 + */ 1.45 + /* we have a private key, not a public key, so don't pass it in */ 1.46 + rv = sec_DecodeSigAlg(NULL, alg, NULL, &signalg, &hashalg); 1.47 + if (rv != SECSuccess) { 1.48 + PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); 1.49 + return 0; 1.50 + } 1.51 + keyType = seckey_GetKeyType(signalg); 1.52 + 1.53 + /* verify our key type */ 1.54 + if (key->keyType != keyType && 1.55 + !((key->keyType == dsaKey) && (keyType == fortezzaKey)) ) { 1.56 + PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); 1.57 + return 0; 1.58 + } 1.59 + 1.60 + cx = (SGNContext*) PORT_ZAlloc(sizeof(SGNContext)); 1.61 + if (cx) { 1.62 + cx->hashalg = hashalg; 1.63 + cx->signalg = signalg; 1.64 + cx->key = key; 1.65 + } 1.66 + return cx; 1.67 +} 1.68 + 1.69 +void 1.70 +SGN_DestroyContext(SGNContext *cx, PRBool freeit) 1.71 +{ 1.72 + if (cx) { 1.73 + if (cx->hashcx != NULL) { 1.74 + (*cx->hashobj->destroy)(cx->hashcx, PR_TRUE); 1.75 + cx->hashcx = NULL; 1.76 + } 1.77 + if (freeit) { 1.78 + PORT_ZFree(cx, sizeof(SGNContext)); 1.79 + } 1.80 + } 1.81 +} 1.82 + 1.83 +SECStatus 1.84 +SGN_Begin(SGNContext *cx) 1.85 +{ 1.86 + if (cx->hashcx != NULL) { 1.87 + (*cx->hashobj->destroy)(cx->hashcx, PR_TRUE); 1.88 + cx->hashcx = NULL; 1.89 + } 1.90 + 1.91 + cx->hashobj = HASH_GetHashObjectByOidTag(cx->hashalg); 1.92 + if (!cx->hashobj) 1.93 + return SECFailure; /* error code is already set */ 1.94 + 1.95 + cx->hashcx = (*cx->hashobj->create)(); 1.96 + if (cx->hashcx == NULL) 1.97 + return SECFailure; 1.98 + 1.99 + (*cx->hashobj->begin)(cx->hashcx); 1.100 + return SECSuccess; 1.101 +} 1.102 + 1.103 +SECStatus 1.104 +SGN_Update(SGNContext *cx, const unsigned char *input, unsigned int inputLen) 1.105 +{ 1.106 + if (cx->hashcx == NULL) { 1.107 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.108 + return SECFailure; 1.109 + } 1.110 + (*cx->hashobj->update)(cx->hashcx, input, inputLen); 1.111 + return SECSuccess; 1.112 +} 1.113 + 1.114 +/* XXX Old template; want to expunge it eventually. */ 1.115 +static DERTemplate SECAlgorithmIDTemplate[] = { 1.116 + { DER_SEQUENCE, 1.117 + 0, NULL, sizeof(SECAlgorithmID) }, 1.118 + { DER_OBJECT_ID, 1.119 + offsetof(SECAlgorithmID,algorithm), }, 1.120 + { DER_OPTIONAL | DER_ANY, 1.121 + offsetof(SECAlgorithmID,parameters), }, 1.122 + { 0, } 1.123 +}; 1.124 + 1.125 +/* 1.126 + * XXX OLD Template. Once all uses have been switched over to new one, 1.127 + * remove this. 1.128 + */ 1.129 +static DERTemplate SGNDigestInfoTemplate[] = { 1.130 + { DER_SEQUENCE, 1.131 + 0, NULL, sizeof(SGNDigestInfo) }, 1.132 + { DER_INLINE, 1.133 + offsetof(SGNDigestInfo,digestAlgorithm), 1.134 + SECAlgorithmIDTemplate, }, 1.135 + { DER_OCTET_STRING, 1.136 + offsetof(SGNDigestInfo,digest), }, 1.137 + { 0, } 1.138 +}; 1.139 + 1.140 +SECStatus 1.141 +SGN_End(SGNContext *cx, SECItem *result) 1.142 +{ 1.143 + unsigned char digest[HASH_LENGTH_MAX]; 1.144 + unsigned part1; 1.145 + int signatureLen; 1.146 + SECStatus rv; 1.147 + SECItem digder, sigitem; 1.148 + PLArenaPool *arena = 0; 1.149 + SECKEYPrivateKey *privKey = cx->key; 1.150 + SGNDigestInfo *di = 0; 1.151 + 1.152 + result->data = 0; 1.153 + digder.data = 0; 1.154 + 1.155 + /* Finish up digest function */ 1.156 + if (cx->hashcx == NULL) { 1.157 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.158 + return SECFailure; 1.159 + } 1.160 + (*cx->hashobj->end)(cx->hashcx, digest, &part1, sizeof(digest)); 1.161 + 1.162 + 1.163 + if (privKey->keyType == rsaKey) { 1.164 + 1.165 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.166 + if ( !arena ) { 1.167 + rv = SECFailure; 1.168 + goto loser; 1.169 + } 1.170 + 1.171 + /* Construct digest info */ 1.172 + di = SGN_CreateDigestInfo(cx->hashalg, digest, part1); 1.173 + if (!di) { 1.174 + rv = SECFailure; 1.175 + goto loser; 1.176 + } 1.177 + 1.178 + /* Der encode the digest as a DigestInfo */ 1.179 + rv = DER_Encode(arena, &digder, SGNDigestInfoTemplate, 1.180 + di); 1.181 + if (rv != SECSuccess) { 1.182 + goto loser; 1.183 + } 1.184 + } else { 1.185 + digder.data = digest; 1.186 + digder.len = part1; 1.187 + } 1.188 + 1.189 + /* 1.190 + ** Encrypt signature after constructing appropriate PKCS#1 signature 1.191 + ** block 1.192 + */ 1.193 + signatureLen = PK11_SignatureLen(privKey); 1.194 + if (signatureLen <= 0) { 1.195 + PORT_SetError(SEC_ERROR_INVALID_KEY); 1.196 + rv = SECFailure; 1.197 + goto loser; 1.198 + } 1.199 + sigitem.len = signatureLen; 1.200 + sigitem.data = (unsigned char*) PORT_Alloc(signatureLen); 1.201 + 1.202 + if (sigitem.data == NULL) { 1.203 + rv = SECFailure; 1.204 + goto loser; 1.205 + } 1.206 + 1.207 + rv = PK11_Sign(privKey, &sigitem, &digder); 1.208 + if (rv != SECSuccess) { 1.209 + PORT_Free(sigitem.data); 1.210 + sigitem.data = NULL; 1.211 + goto loser; 1.212 + } 1.213 + 1.214 + if ((cx->signalg == SEC_OID_ANSIX9_DSA_SIGNATURE) || 1.215 + (cx->signalg == SEC_OID_ANSIX962_EC_PUBLIC_KEY)) { 1.216 + /* DSAU_EncodeDerSigWithLen works for DSA and ECDSA */ 1.217 + rv = DSAU_EncodeDerSigWithLen(result, &sigitem, sigitem.len); 1.218 + PORT_Free(sigitem.data); 1.219 + if (rv != SECSuccess) 1.220 + goto loser; 1.221 + } else { 1.222 + result->len = sigitem.len; 1.223 + result->data = sigitem.data; 1.224 + } 1.225 + 1.226 + loser: 1.227 + SGN_DestroyDigestInfo(di); 1.228 + if (arena != NULL) { 1.229 + PORT_FreeArena(arena, PR_FALSE); 1.230 + } 1.231 + return rv; 1.232 +} 1.233 + 1.234 +/************************************************************************/ 1.235 + 1.236 +/* 1.237 +** Sign a block of data returning in result a bunch of bytes that are the 1.238 +** signature. Returns zero on success, an error code on failure. 1.239 +*/ 1.240 +SECStatus 1.241 +SEC_SignData(SECItem *res, const unsigned char *buf, int len, 1.242 + SECKEYPrivateKey *pk, SECOidTag algid) 1.243 +{ 1.244 + SECStatus rv; 1.245 + SGNContext *sgn; 1.246 + 1.247 + 1.248 + sgn = SGN_NewContext(algid, pk); 1.249 + 1.250 + if (sgn == NULL) 1.251 + return SECFailure; 1.252 + 1.253 + rv = SGN_Begin(sgn); 1.254 + if (rv != SECSuccess) 1.255 + goto loser; 1.256 + 1.257 + rv = SGN_Update(sgn, buf, len); 1.258 + if (rv != SECSuccess) 1.259 + goto loser; 1.260 + 1.261 + rv = SGN_End(sgn, res); 1.262 + 1.263 + loser: 1.264 + SGN_DestroyContext(sgn, PR_TRUE); 1.265 + return rv; 1.266 +} 1.267 + 1.268 +/************************************************************************/ 1.269 + 1.270 +DERTemplate CERTSignedDataTemplate[] = 1.271 +{ 1.272 + { DER_SEQUENCE, 1.273 + 0, NULL, sizeof(CERTSignedData) }, 1.274 + { DER_ANY, 1.275 + offsetof(CERTSignedData,data), }, 1.276 + { DER_INLINE, 1.277 + offsetof(CERTSignedData,signatureAlgorithm), 1.278 + SECAlgorithmIDTemplate, }, 1.279 + { DER_BIT_STRING, 1.280 + offsetof(CERTSignedData,signature), }, 1.281 + { 0, } 1.282 +}; 1.283 + 1.284 +SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate) 1.285 + 1.286 +const SEC_ASN1Template CERT_SignedDataTemplate[] = 1.287 +{ 1.288 + { SEC_ASN1_SEQUENCE, 1.289 + 0, NULL, sizeof(CERTSignedData) }, 1.290 + { SEC_ASN1_ANY, 1.291 + offsetof(CERTSignedData,data), }, 1.292 + { SEC_ASN1_INLINE | SEC_ASN1_XTRN, 1.293 + offsetof(CERTSignedData,signatureAlgorithm), 1.294 + SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate), }, 1.295 + { SEC_ASN1_BIT_STRING, 1.296 + offsetof(CERTSignedData,signature), }, 1.297 + { 0, } 1.298 +}; 1.299 + 1.300 +SEC_ASN1_CHOOSER_IMPLEMENT(CERT_SignedDataTemplate) 1.301 + 1.302 + 1.303 +SECStatus 1.304 +SEC_DerSignData(PLArenaPool *arena, SECItem *result, 1.305 + const unsigned char *buf, int len, SECKEYPrivateKey *pk, 1.306 + SECOidTag algID) 1.307 +{ 1.308 + SECItem it; 1.309 + CERTSignedData sd; 1.310 + SECStatus rv; 1.311 + 1.312 + it.data = 0; 1.313 + 1.314 + /* XXX We should probably have some asserts here to make sure the key type 1.315 + * and algID match 1.316 + */ 1.317 + 1.318 + if (algID == SEC_OID_UNKNOWN) { 1.319 + switch(pk->keyType) { 1.320 + case rsaKey: 1.321 + algID = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION; 1.322 + break; 1.323 + case dsaKey: 1.324 + /* get Signature length (= q_len*2) and work from there */ 1.325 + switch (PK11_SignatureLen(pk)) { 1.326 + case 448: 1.327 + algID = SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA224_DIGEST; 1.328 + break; 1.329 + case 512: 1.330 + algID = SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA256_DIGEST; 1.331 + break; 1.332 + default: 1.333 + algID = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST; 1.334 + break; 1.335 + } 1.336 + break; 1.337 + case ecKey: 1.338 + algID = SEC_OID_ANSIX962_ECDSA_SIGNATURE_WITH_SHA1_DIGEST; 1.339 + break; 1.340 + default: 1.341 + PORT_SetError(SEC_ERROR_INVALID_KEY); 1.342 + return SECFailure; 1.343 + } 1.344 + } 1.345 + 1.346 + /* Sign input buffer */ 1.347 + rv = SEC_SignData(&it, buf, len, pk, algID); 1.348 + if (rv) goto loser; 1.349 + 1.350 + /* Fill out SignedData object */ 1.351 + PORT_Memset(&sd, 0, sizeof(sd)); 1.352 + sd.data.data = (unsigned char*) buf; 1.353 + sd.data.len = len; 1.354 + sd.signature.data = it.data; 1.355 + sd.signature.len = it.len << 3; /* convert to bit string */ 1.356 + rv = SECOID_SetAlgorithmID(arena, &sd.signatureAlgorithm, algID, 0); 1.357 + if (rv) goto loser; 1.358 + 1.359 + /* DER encode the signed data object */ 1.360 + rv = DER_Encode(arena, result, CERTSignedDataTemplate, &sd); 1.361 + /* FALL THROUGH */ 1.362 + 1.363 + loser: 1.364 + PORT_Free(it.data); 1.365 + return rv; 1.366 +} 1.367 + 1.368 +SECStatus 1.369 +SGN_Digest(SECKEYPrivateKey *privKey, 1.370 + SECOidTag algtag, SECItem *result, SECItem *digest) 1.371 +{ 1.372 + int modulusLen; 1.373 + SECStatus rv; 1.374 + SECItem digder; 1.375 + PLArenaPool *arena = 0; 1.376 + SGNDigestInfo *di = 0; 1.377 + 1.378 + 1.379 + result->data = 0; 1.380 + 1.381 + if (privKey->keyType == rsaKey) { 1.382 + 1.383 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.384 + if ( !arena ) { 1.385 + rv = SECFailure; 1.386 + goto loser; 1.387 + } 1.388 + 1.389 + /* Construct digest info */ 1.390 + di = SGN_CreateDigestInfo(algtag, digest->data, digest->len); 1.391 + if (!di) { 1.392 + rv = SECFailure; 1.393 + goto loser; 1.394 + } 1.395 + 1.396 + /* Der encode the digest as a DigestInfo */ 1.397 + rv = DER_Encode(arena, &digder, SGNDigestInfoTemplate, 1.398 + di); 1.399 + if (rv != SECSuccess) { 1.400 + goto loser; 1.401 + } 1.402 + } else { 1.403 + digder.data = digest->data; 1.404 + digder.len = digest->len; 1.405 + } 1.406 + 1.407 + /* 1.408 + ** Encrypt signature after constructing appropriate PKCS#1 signature 1.409 + ** block 1.410 + */ 1.411 + modulusLen = PK11_SignatureLen(privKey); 1.412 + if (modulusLen <= 0) { 1.413 + PORT_SetError(SEC_ERROR_INVALID_KEY); 1.414 + rv = SECFailure; 1.415 + goto loser; 1.416 + } 1.417 + result->len = modulusLen; 1.418 + result->data = (unsigned char*) PORT_Alloc(modulusLen); 1.419 + 1.420 + if (result->data == NULL) { 1.421 + rv = SECFailure; 1.422 + goto loser; 1.423 + } 1.424 + 1.425 + rv = PK11_Sign(privKey, result, &digder); 1.426 + if (rv != SECSuccess) { 1.427 + PORT_Free(result->data); 1.428 + result->data = NULL; 1.429 + } 1.430 + 1.431 + loser: 1.432 + SGN_DestroyDigestInfo(di); 1.433 + if (arena != NULL) { 1.434 + PORT_FreeArena(arena, PR_FALSE); 1.435 + } 1.436 + return rv; 1.437 +} 1.438 + 1.439 +SECOidTag 1.440 +SEC_GetSignatureAlgorithmOidTag(KeyType keyType, SECOidTag hashAlgTag) 1.441 +{ 1.442 + SECOidTag sigTag = SEC_OID_UNKNOWN; 1.443 + 1.444 + switch (keyType) { 1.445 + case rsaKey: 1.446 + switch (hashAlgTag) { 1.447 + case SEC_OID_MD2: 1.448 + sigTag = SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION; break; 1.449 + case SEC_OID_MD5: 1.450 + sigTag = SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION; break; 1.451 + case SEC_OID_UNKNOWN: /* default for RSA if not specified */ 1.452 + case SEC_OID_SHA1: 1.453 + sigTag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION; break; 1.454 + case SEC_OID_SHA224: 1.455 + sigTag = SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION; break; 1.456 + case SEC_OID_SHA256: 1.457 + sigTag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION; break; 1.458 + case SEC_OID_SHA384: 1.459 + sigTag = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION; break; 1.460 + case SEC_OID_SHA512: 1.461 + sigTag = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION; break; 1.462 + default: 1.463 + break; 1.464 + } 1.465 + break; 1.466 + case dsaKey: 1.467 + switch (hashAlgTag) { 1.468 + case SEC_OID_UNKNOWN: /* default for DSA if not specified */ 1.469 + case SEC_OID_SHA1: 1.470 + sigTag = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST; break; 1.471 + case SEC_OID_SHA224: 1.472 + sigTag = SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA224_DIGEST; break; 1.473 + case SEC_OID_SHA256: 1.474 + sigTag = SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA256_DIGEST; break; 1.475 + default: 1.476 + break; 1.477 + } 1.478 + break; 1.479 + case ecKey: 1.480 + switch (hashAlgTag) { 1.481 + case SEC_OID_UNKNOWN: /* default for ECDSA if not specified */ 1.482 + case SEC_OID_SHA1: 1.483 + sigTag = SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE; break; 1.484 + case SEC_OID_SHA224: 1.485 + sigTag = SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE; break; 1.486 + case SEC_OID_SHA256: 1.487 + sigTag = SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE; break; 1.488 + case SEC_OID_SHA384: 1.489 + sigTag = SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE; break; 1.490 + case SEC_OID_SHA512: 1.491 + sigTag = SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE; break; 1.492 + default: 1.493 + break; 1.494 + } 1.495 + default: 1.496 + break; 1.497 + } 1.498 + return sigTag; 1.499 +}