security/nss/lib/cryptohi/secsign.c

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

michael@0 1 /*
michael@0 2 * Signature stuff.
michael@0 3 *
michael@0 4 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 5 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 7
michael@0 8 #include <stdio.h>
michael@0 9 #include "cryptohi.h"
michael@0 10 #include "sechash.h"
michael@0 11 #include "secder.h"
michael@0 12 #include "keyhi.h"
michael@0 13 #include "secoid.h"
michael@0 14 #include "secdig.h"
michael@0 15 #include "pk11func.h"
michael@0 16 #include "secerr.h"
michael@0 17 #include "keyi.h"
michael@0 18
michael@0 19 struct SGNContextStr {
michael@0 20 SECOidTag signalg;
michael@0 21 SECOidTag hashalg;
michael@0 22 void *hashcx;
michael@0 23 const SECHashObject *hashobj;
michael@0 24 SECKEYPrivateKey *key;
michael@0 25 };
michael@0 26
michael@0 27 SGNContext *
michael@0 28 SGN_NewContext(SECOidTag alg, SECKEYPrivateKey *key)
michael@0 29 {
michael@0 30 SGNContext *cx;
michael@0 31 SECOidTag hashalg, signalg;
michael@0 32 KeyType keyType;
michael@0 33 SECStatus rv;
michael@0 34
michael@0 35 /* OK, map a PKCS #7 hash and encrypt algorithm into
michael@0 36 * a standard hashing algorithm. Why did we pass in the whole
michael@0 37 * PKCS #7 algTag if we were just going to change here you might
michael@0 38 * ask. Well the answer is for some cards we may have to do the
michael@0 39 * hashing on card. It may not support CKM_RSA_PKCS sign algorithm,
michael@0 40 * it may just support CKM_SHA1_RSA_PKCS and/or CKM_MD5_RSA_PKCS.
michael@0 41 */
michael@0 42 /* we have a private key, not a public key, so don't pass it in */
michael@0 43 rv = sec_DecodeSigAlg(NULL, alg, NULL, &signalg, &hashalg);
michael@0 44 if (rv != SECSuccess) {
michael@0 45 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
michael@0 46 return 0;
michael@0 47 }
michael@0 48 keyType = seckey_GetKeyType(signalg);
michael@0 49
michael@0 50 /* verify our key type */
michael@0 51 if (key->keyType != keyType &&
michael@0 52 !((key->keyType == dsaKey) && (keyType == fortezzaKey)) ) {
michael@0 53 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
michael@0 54 return 0;
michael@0 55 }
michael@0 56
michael@0 57 cx = (SGNContext*) PORT_ZAlloc(sizeof(SGNContext));
michael@0 58 if (cx) {
michael@0 59 cx->hashalg = hashalg;
michael@0 60 cx->signalg = signalg;
michael@0 61 cx->key = key;
michael@0 62 }
michael@0 63 return cx;
michael@0 64 }
michael@0 65
michael@0 66 void
michael@0 67 SGN_DestroyContext(SGNContext *cx, PRBool freeit)
michael@0 68 {
michael@0 69 if (cx) {
michael@0 70 if (cx->hashcx != NULL) {
michael@0 71 (*cx->hashobj->destroy)(cx->hashcx, PR_TRUE);
michael@0 72 cx->hashcx = NULL;
michael@0 73 }
michael@0 74 if (freeit) {
michael@0 75 PORT_ZFree(cx, sizeof(SGNContext));
michael@0 76 }
michael@0 77 }
michael@0 78 }
michael@0 79
michael@0 80 SECStatus
michael@0 81 SGN_Begin(SGNContext *cx)
michael@0 82 {
michael@0 83 if (cx->hashcx != NULL) {
michael@0 84 (*cx->hashobj->destroy)(cx->hashcx, PR_TRUE);
michael@0 85 cx->hashcx = NULL;
michael@0 86 }
michael@0 87
michael@0 88 cx->hashobj = HASH_GetHashObjectByOidTag(cx->hashalg);
michael@0 89 if (!cx->hashobj)
michael@0 90 return SECFailure; /* error code is already set */
michael@0 91
michael@0 92 cx->hashcx = (*cx->hashobj->create)();
michael@0 93 if (cx->hashcx == NULL)
michael@0 94 return SECFailure;
michael@0 95
michael@0 96 (*cx->hashobj->begin)(cx->hashcx);
michael@0 97 return SECSuccess;
michael@0 98 }
michael@0 99
michael@0 100 SECStatus
michael@0 101 SGN_Update(SGNContext *cx, const unsigned char *input, unsigned int inputLen)
michael@0 102 {
michael@0 103 if (cx->hashcx == NULL) {
michael@0 104 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 105 return SECFailure;
michael@0 106 }
michael@0 107 (*cx->hashobj->update)(cx->hashcx, input, inputLen);
michael@0 108 return SECSuccess;
michael@0 109 }
michael@0 110
michael@0 111 /* XXX Old template; want to expunge it eventually. */
michael@0 112 static DERTemplate SECAlgorithmIDTemplate[] = {
michael@0 113 { DER_SEQUENCE,
michael@0 114 0, NULL, sizeof(SECAlgorithmID) },
michael@0 115 { DER_OBJECT_ID,
michael@0 116 offsetof(SECAlgorithmID,algorithm), },
michael@0 117 { DER_OPTIONAL | DER_ANY,
michael@0 118 offsetof(SECAlgorithmID,parameters), },
michael@0 119 { 0, }
michael@0 120 };
michael@0 121
michael@0 122 /*
michael@0 123 * XXX OLD Template. Once all uses have been switched over to new one,
michael@0 124 * remove this.
michael@0 125 */
michael@0 126 static DERTemplate SGNDigestInfoTemplate[] = {
michael@0 127 { DER_SEQUENCE,
michael@0 128 0, NULL, sizeof(SGNDigestInfo) },
michael@0 129 { DER_INLINE,
michael@0 130 offsetof(SGNDigestInfo,digestAlgorithm),
michael@0 131 SECAlgorithmIDTemplate, },
michael@0 132 { DER_OCTET_STRING,
michael@0 133 offsetof(SGNDigestInfo,digest), },
michael@0 134 { 0, }
michael@0 135 };
michael@0 136
michael@0 137 SECStatus
michael@0 138 SGN_End(SGNContext *cx, SECItem *result)
michael@0 139 {
michael@0 140 unsigned char digest[HASH_LENGTH_MAX];
michael@0 141 unsigned part1;
michael@0 142 int signatureLen;
michael@0 143 SECStatus rv;
michael@0 144 SECItem digder, sigitem;
michael@0 145 PLArenaPool *arena = 0;
michael@0 146 SECKEYPrivateKey *privKey = cx->key;
michael@0 147 SGNDigestInfo *di = 0;
michael@0 148
michael@0 149 result->data = 0;
michael@0 150 digder.data = 0;
michael@0 151
michael@0 152 /* Finish up digest function */
michael@0 153 if (cx->hashcx == NULL) {
michael@0 154 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 155 return SECFailure;
michael@0 156 }
michael@0 157 (*cx->hashobj->end)(cx->hashcx, digest, &part1, sizeof(digest));
michael@0 158
michael@0 159
michael@0 160 if (privKey->keyType == rsaKey) {
michael@0 161
michael@0 162 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
michael@0 163 if ( !arena ) {
michael@0 164 rv = SECFailure;
michael@0 165 goto loser;
michael@0 166 }
michael@0 167
michael@0 168 /* Construct digest info */
michael@0 169 di = SGN_CreateDigestInfo(cx->hashalg, digest, part1);
michael@0 170 if (!di) {
michael@0 171 rv = SECFailure;
michael@0 172 goto loser;
michael@0 173 }
michael@0 174
michael@0 175 /* Der encode the digest as a DigestInfo */
michael@0 176 rv = DER_Encode(arena, &digder, SGNDigestInfoTemplate,
michael@0 177 di);
michael@0 178 if (rv != SECSuccess) {
michael@0 179 goto loser;
michael@0 180 }
michael@0 181 } else {
michael@0 182 digder.data = digest;
michael@0 183 digder.len = part1;
michael@0 184 }
michael@0 185
michael@0 186 /*
michael@0 187 ** Encrypt signature after constructing appropriate PKCS#1 signature
michael@0 188 ** block
michael@0 189 */
michael@0 190 signatureLen = PK11_SignatureLen(privKey);
michael@0 191 if (signatureLen <= 0) {
michael@0 192 PORT_SetError(SEC_ERROR_INVALID_KEY);
michael@0 193 rv = SECFailure;
michael@0 194 goto loser;
michael@0 195 }
michael@0 196 sigitem.len = signatureLen;
michael@0 197 sigitem.data = (unsigned char*) PORT_Alloc(signatureLen);
michael@0 198
michael@0 199 if (sigitem.data == NULL) {
michael@0 200 rv = SECFailure;
michael@0 201 goto loser;
michael@0 202 }
michael@0 203
michael@0 204 rv = PK11_Sign(privKey, &sigitem, &digder);
michael@0 205 if (rv != SECSuccess) {
michael@0 206 PORT_Free(sigitem.data);
michael@0 207 sigitem.data = NULL;
michael@0 208 goto loser;
michael@0 209 }
michael@0 210
michael@0 211 if ((cx->signalg == SEC_OID_ANSIX9_DSA_SIGNATURE) ||
michael@0 212 (cx->signalg == SEC_OID_ANSIX962_EC_PUBLIC_KEY)) {
michael@0 213 /* DSAU_EncodeDerSigWithLen works for DSA and ECDSA */
michael@0 214 rv = DSAU_EncodeDerSigWithLen(result, &sigitem, sigitem.len);
michael@0 215 PORT_Free(sigitem.data);
michael@0 216 if (rv != SECSuccess)
michael@0 217 goto loser;
michael@0 218 } else {
michael@0 219 result->len = sigitem.len;
michael@0 220 result->data = sigitem.data;
michael@0 221 }
michael@0 222
michael@0 223 loser:
michael@0 224 SGN_DestroyDigestInfo(di);
michael@0 225 if (arena != NULL) {
michael@0 226 PORT_FreeArena(arena, PR_FALSE);
michael@0 227 }
michael@0 228 return rv;
michael@0 229 }
michael@0 230
michael@0 231 /************************************************************************/
michael@0 232
michael@0 233 /*
michael@0 234 ** Sign a block of data returning in result a bunch of bytes that are the
michael@0 235 ** signature. Returns zero on success, an error code on failure.
michael@0 236 */
michael@0 237 SECStatus
michael@0 238 SEC_SignData(SECItem *res, const unsigned char *buf, int len,
michael@0 239 SECKEYPrivateKey *pk, SECOidTag algid)
michael@0 240 {
michael@0 241 SECStatus rv;
michael@0 242 SGNContext *sgn;
michael@0 243
michael@0 244
michael@0 245 sgn = SGN_NewContext(algid, pk);
michael@0 246
michael@0 247 if (sgn == NULL)
michael@0 248 return SECFailure;
michael@0 249
michael@0 250 rv = SGN_Begin(sgn);
michael@0 251 if (rv != SECSuccess)
michael@0 252 goto loser;
michael@0 253
michael@0 254 rv = SGN_Update(sgn, buf, len);
michael@0 255 if (rv != SECSuccess)
michael@0 256 goto loser;
michael@0 257
michael@0 258 rv = SGN_End(sgn, res);
michael@0 259
michael@0 260 loser:
michael@0 261 SGN_DestroyContext(sgn, PR_TRUE);
michael@0 262 return rv;
michael@0 263 }
michael@0 264
michael@0 265 /************************************************************************/
michael@0 266
michael@0 267 DERTemplate CERTSignedDataTemplate[] =
michael@0 268 {
michael@0 269 { DER_SEQUENCE,
michael@0 270 0, NULL, sizeof(CERTSignedData) },
michael@0 271 { DER_ANY,
michael@0 272 offsetof(CERTSignedData,data), },
michael@0 273 { DER_INLINE,
michael@0 274 offsetof(CERTSignedData,signatureAlgorithm),
michael@0 275 SECAlgorithmIDTemplate, },
michael@0 276 { DER_BIT_STRING,
michael@0 277 offsetof(CERTSignedData,signature), },
michael@0 278 { 0, }
michael@0 279 };
michael@0 280
michael@0 281 SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
michael@0 282
michael@0 283 const SEC_ASN1Template CERT_SignedDataTemplate[] =
michael@0 284 {
michael@0 285 { SEC_ASN1_SEQUENCE,
michael@0 286 0, NULL, sizeof(CERTSignedData) },
michael@0 287 { SEC_ASN1_ANY,
michael@0 288 offsetof(CERTSignedData,data), },
michael@0 289 { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
michael@0 290 offsetof(CERTSignedData,signatureAlgorithm),
michael@0 291 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate), },
michael@0 292 { SEC_ASN1_BIT_STRING,
michael@0 293 offsetof(CERTSignedData,signature), },
michael@0 294 { 0, }
michael@0 295 };
michael@0 296
michael@0 297 SEC_ASN1_CHOOSER_IMPLEMENT(CERT_SignedDataTemplate)
michael@0 298
michael@0 299
michael@0 300 SECStatus
michael@0 301 SEC_DerSignData(PLArenaPool *arena, SECItem *result,
michael@0 302 const unsigned char *buf, int len, SECKEYPrivateKey *pk,
michael@0 303 SECOidTag algID)
michael@0 304 {
michael@0 305 SECItem it;
michael@0 306 CERTSignedData sd;
michael@0 307 SECStatus rv;
michael@0 308
michael@0 309 it.data = 0;
michael@0 310
michael@0 311 /* XXX We should probably have some asserts here to make sure the key type
michael@0 312 * and algID match
michael@0 313 */
michael@0 314
michael@0 315 if (algID == SEC_OID_UNKNOWN) {
michael@0 316 switch(pk->keyType) {
michael@0 317 case rsaKey:
michael@0 318 algID = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION;
michael@0 319 break;
michael@0 320 case dsaKey:
michael@0 321 /* get Signature length (= q_len*2) and work from there */
michael@0 322 switch (PK11_SignatureLen(pk)) {
michael@0 323 case 448:
michael@0 324 algID = SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA224_DIGEST;
michael@0 325 break;
michael@0 326 case 512:
michael@0 327 algID = SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA256_DIGEST;
michael@0 328 break;
michael@0 329 default:
michael@0 330 algID = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST;
michael@0 331 break;
michael@0 332 }
michael@0 333 break;
michael@0 334 case ecKey:
michael@0 335 algID = SEC_OID_ANSIX962_ECDSA_SIGNATURE_WITH_SHA1_DIGEST;
michael@0 336 break;
michael@0 337 default:
michael@0 338 PORT_SetError(SEC_ERROR_INVALID_KEY);
michael@0 339 return SECFailure;
michael@0 340 }
michael@0 341 }
michael@0 342
michael@0 343 /* Sign input buffer */
michael@0 344 rv = SEC_SignData(&it, buf, len, pk, algID);
michael@0 345 if (rv) goto loser;
michael@0 346
michael@0 347 /* Fill out SignedData object */
michael@0 348 PORT_Memset(&sd, 0, sizeof(sd));
michael@0 349 sd.data.data = (unsigned char*) buf;
michael@0 350 sd.data.len = len;
michael@0 351 sd.signature.data = it.data;
michael@0 352 sd.signature.len = it.len << 3; /* convert to bit string */
michael@0 353 rv = SECOID_SetAlgorithmID(arena, &sd.signatureAlgorithm, algID, 0);
michael@0 354 if (rv) goto loser;
michael@0 355
michael@0 356 /* DER encode the signed data object */
michael@0 357 rv = DER_Encode(arena, result, CERTSignedDataTemplate, &sd);
michael@0 358 /* FALL THROUGH */
michael@0 359
michael@0 360 loser:
michael@0 361 PORT_Free(it.data);
michael@0 362 return rv;
michael@0 363 }
michael@0 364
michael@0 365 SECStatus
michael@0 366 SGN_Digest(SECKEYPrivateKey *privKey,
michael@0 367 SECOidTag algtag, SECItem *result, SECItem *digest)
michael@0 368 {
michael@0 369 int modulusLen;
michael@0 370 SECStatus rv;
michael@0 371 SECItem digder;
michael@0 372 PLArenaPool *arena = 0;
michael@0 373 SGNDigestInfo *di = 0;
michael@0 374
michael@0 375
michael@0 376 result->data = 0;
michael@0 377
michael@0 378 if (privKey->keyType == rsaKey) {
michael@0 379
michael@0 380 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
michael@0 381 if ( !arena ) {
michael@0 382 rv = SECFailure;
michael@0 383 goto loser;
michael@0 384 }
michael@0 385
michael@0 386 /* Construct digest info */
michael@0 387 di = SGN_CreateDigestInfo(algtag, digest->data, digest->len);
michael@0 388 if (!di) {
michael@0 389 rv = SECFailure;
michael@0 390 goto loser;
michael@0 391 }
michael@0 392
michael@0 393 /* Der encode the digest as a DigestInfo */
michael@0 394 rv = DER_Encode(arena, &digder, SGNDigestInfoTemplate,
michael@0 395 di);
michael@0 396 if (rv != SECSuccess) {
michael@0 397 goto loser;
michael@0 398 }
michael@0 399 } else {
michael@0 400 digder.data = digest->data;
michael@0 401 digder.len = digest->len;
michael@0 402 }
michael@0 403
michael@0 404 /*
michael@0 405 ** Encrypt signature after constructing appropriate PKCS#1 signature
michael@0 406 ** block
michael@0 407 */
michael@0 408 modulusLen = PK11_SignatureLen(privKey);
michael@0 409 if (modulusLen <= 0) {
michael@0 410 PORT_SetError(SEC_ERROR_INVALID_KEY);
michael@0 411 rv = SECFailure;
michael@0 412 goto loser;
michael@0 413 }
michael@0 414 result->len = modulusLen;
michael@0 415 result->data = (unsigned char*) PORT_Alloc(modulusLen);
michael@0 416
michael@0 417 if (result->data == NULL) {
michael@0 418 rv = SECFailure;
michael@0 419 goto loser;
michael@0 420 }
michael@0 421
michael@0 422 rv = PK11_Sign(privKey, result, &digder);
michael@0 423 if (rv != SECSuccess) {
michael@0 424 PORT_Free(result->data);
michael@0 425 result->data = NULL;
michael@0 426 }
michael@0 427
michael@0 428 loser:
michael@0 429 SGN_DestroyDigestInfo(di);
michael@0 430 if (arena != NULL) {
michael@0 431 PORT_FreeArena(arena, PR_FALSE);
michael@0 432 }
michael@0 433 return rv;
michael@0 434 }
michael@0 435
michael@0 436 SECOidTag
michael@0 437 SEC_GetSignatureAlgorithmOidTag(KeyType keyType, SECOidTag hashAlgTag)
michael@0 438 {
michael@0 439 SECOidTag sigTag = SEC_OID_UNKNOWN;
michael@0 440
michael@0 441 switch (keyType) {
michael@0 442 case rsaKey:
michael@0 443 switch (hashAlgTag) {
michael@0 444 case SEC_OID_MD2:
michael@0 445 sigTag = SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION; break;
michael@0 446 case SEC_OID_MD5:
michael@0 447 sigTag = SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION; break;
michael@0 448 case SEC_OID_UNKNOWN: /* default for RSA if not specified */
michael@0 449 case SEC_OID_SHA1:
michael@0 450 sigTag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION; break;
michael@0 451 case SEC_OID_SHA224:
michael@0 452 sigTag = SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION; break;
michael@0 453 case SEC_OID_SHA256:
michael@0 454 sigTag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION; break;
michael@0 455 case SEC_OID_SHA384:
michael@0 456 sigTag = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION; break;
michael@0 457 case SEC_OID_SHA512:
michael@0 458 sigTag = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION; break;
michael@0 459 default:
michael@0 460 break;
michael@0 461 }
michael@0 462 break;
michael@0 463 case dsaKey:
michael@0 464 switch (hashAlgTag) {
michael@0 465 case SEC_OID_UNKNOWN: /* default for DSA if not specified */
michael@0 466 case SEC_OID_SHA1:
michael@0 467 sigTag = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST; break;
michael@0 468 case SEC_OID_SHA224:
michael@0 469 sigTag = SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA224_DIGEST; break;
michael@0 470 case SEC_OID_SHA256:
michael@0 471 sigTag = SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA256_DIGEST; break;
michael@0 472 default:
michael@0 473 break;
michael@0 474 }
michael@0 475 break;
michael@0 476 case ecKey:
michael@0 477 switch (hashAlgTag) {
michael@0 478 case SEC_OID_UNKNOWN: /* default for ECDSA if not specified */
michael@0 479 case SEC_OID_SHA1:
michael@0 480 sigTag = SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE; break;
michael@0 481 case SEC_OID_SHA224:
michael@0 482 sigTag = SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE; break;
michael@0 483 case SEC_OID_SHA256:
michael@0 484 sigTag = SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE; break;
michael@0 485 case SEC_OID_SHA384:
michael@0 486 sigTag = SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE; break;
michael@0 487 case SEC_OID_SHA512:
michael@0 488 sigTag = SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE; break;
michael@0 489 default:
michael@0 490 break;
michael@0 491 }
michael@0 492 default:
michael@0 493 break;
michael@0 494 }
michael@0 495 return sigTag;
michael@0 496 }

mercurial