security/nss/lib/freebl/rsapkcs.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
michael@0 5 /*
michael@0 6 * RSA PKCS#1 v2.1 (RFC 3447) operations
michael@0 7 */
michael@0 8
michael@0 9 #ifdef FREEBL_NO_DEPEND
michael@0 10 #include "stubs.h"
michael@0 11 #endif
michael@0 12
michael@0 13 #include "secerr.h"
michael@0 14
michael@0 15 #include "blapi.h"
michael@0 16 #include "secitem.h"
michael@0 17 #include "blapii.h"
michael@0 18
michael@0 19 #define RSA_BLOCK_MIN_PAD_LEN 8
michael@0 20 #define RSA_BLOCK_FIRST_OCTET 0x00
michael@0 21 #define RSA_BLOCK_PRIVATE_PAD_OCTET 0xff
michael@0 22 #define RSA_BLOCK_AFTER_PAD_OCTET 0x00
michael@0 23
michael@0 24 /*
michael@0 25 * RSA block types
michael@0 26 *
michael@0 27 * The values of RSA_BlockPrivate and RSA_BlockPublic are fixed.
michael@0 28 * The value of RSA_BlockRaw isn't fixed by definition, but we are keeping
michael@0 29 * the value that NSS has been using in the past.
michael@0 30 */
michael@0 31 typedef enum {
michael@0 32 RSA_BlockPrivate = 1, /* pad for a private-key operation */
michael@0 33 RSA_BlockPublic = 2, /* pad for a public-key operation */
michael@0 34 RSA_BlockRaw = 4 /* simply justify the block appropriately */
michael@0 35 } RSA_BlockType;
michael@0 36
michael@0 37 /* Needed for RSA-PSS functions */
michael@0 38 static const unsigned char eightZeros[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
michael@0 39
michael@0 40 /* Constant time comparison of a single byte.
michael@0 41 * Returns 1 iff a == b, otherwise returns 0.
michael@0 42 * Note: For ranges of bytes, use constantTimeCompare.
michael@0 43 */
michael@0 44 static unsigned char constantTimeEQ8(unsigned char a, unsigned char b) {
michael@0 45 unsigned char c = ~((a - b) | (b - a));
michael@0 46 c >>= 7;
michael@0 47 return c;
michael@0 48 }
michael@0 49
michael@0 50 /* Constant time comparison of a range of bytes.
michael@0 51 * Returns 1 iff len bytes of a are identical to len bytes of b, otherwise
michael@0 52 * returns 0.
michael@0 53 */
michael@0 54 static unsigned char constantTimeCompare(const unsigned char *a,
michael@0 55 const unsigned char *b,
michael@0 56 unsigned int len) {
michael@0 57 unsigned char tmp = 0;
michael@0 58 unsigned int i;
michael@0 59 for (i = 0; i < len; ++i, ++a, ++b)
michael@0 60 tmp |= *a ^ *b;
michael@0 61 return constantTimeEQ8(0x00, tmp);
michael@0 62 }
michael@0 63
michael@0 64 /* Constant time conditional.
michael@0 65 * Returns a if c is 1, or b if c is 0. The result is undefined if c is
michael@0 66 * not 0 or 1.
michael@0 67 */
michael@0 68 static unsigned int constantTimeCondition(unsigned int c,
michael@0 69 unsigned int a,
michael@0 70 unsigned int b)
michael@0 71 {
michael@0 72 return (~(c - 1) & a) | ((c - 1) & b);
michael@0 73 }
michael@0 74
michael@0 75 static unsigned int
michael@0 76 rsa_modulusLen(SECItem * modulus)
michael@0 77 {
michael@0 78 unsigned char byteZero = modulus->data[0];
michael@0 79 unsigned int modLen = modulus->len - !byteZero;
michael@0 80 return modLen;
michael@0 81 }
michael@0 82
michael@0 83 /*
michael@0 84 * Format one block of data for public/private key encryption using
michael@0 85 * the rules defined in PKCS #1.
michael@0 86 */
michael@0 87 static unsigned char *
michael@0 88 rsa_FormatOneBlock(unsigned modulusLen,
michael@0 89 RSA_BlockType blockType,
michael@0 90 SECItem * data)
michael@0 91 {
michael@0 92 unsigned char *block;
michael@0 93 unsigned char *bp;
michael@0 94 int padLen;
michael@0 95 int i, j;
michael@0 96 SECStatus rv;
michael@0 97
michael@0 98 block = (unsigned char *) PORT_Alloc(modulusLen);
michael@0 99 if (block == NULL)
michael@0 100 return NULL;
michael@0 101
michael@0 102 bp = block;
michael@0 103
michael@0 104 /*
michael@0 105 * All RSA blocks start with two octets:
michael@0 106 * 0x00 || BlockType
michael@0 107 */
michael@0 108 *bp++ = RSA_BLOCK_FIRST_OCTET;
michael@0 109 *bp++ = (unsigned char) blockType;
michael@0 110
michael@0 111 switch (blockType) {
michael@0 112
michael@0 113 /*
michael@0 114 * Blocks intended for private-key operation.
michael@0 115 */
michael@0 116 case RSA_BlockPrivate: /* preferred method */
michael@0 117 /*
michael@0 118 * 0x00 || BT || Pad || 0x00 || ActualData
michael@0 119 * 1 1 padLen 1 data->len
michael@0 120 * Pad is either all 0x00 or all 0xff bytes, depending on blockType.
michael@0 121 */
michael@0 122 padLen = modulusLen - data->len - 3;
michael@0 123 PORT_Assert(padLen >= RSA_BLOCK_MIN_PAD_LEN);
michael@0 124 if (padLen < RSA_BLOCK_MIN_PAD_LEN) {
michael@0 125 PORT_Free(block);
michael@0 126 return NULL;
michael@0 127 }
michael@0 128 PORT_Memset(bp, RSA_BLOCK_PRIVATE_PAD_OCTET, padLen);
michael@0 129 bp += padLen;
michael@0 130 *bp++ = RSA_BLOCK_AFTER_PAD_OCTET;
michael@0 131 PORT_Memcpy(bp, data->data, data->len);
michael@0 132 break;
michael@0 133
michael@0 134 /*
michael@0 135 * Blocks intended for public-key operation.
michael@0 136 */
michael@0 137 case RSA_BlockPublic:
michael@0 138 /*
michael@0 139 * 0x00 || BT || Pad || 0x00 || ActualData
michael@0 140 * 1 1 padLen 1 data->len
michael@0 141 * Pad is all non-zero random bytes.
michael@0 142 *
michael@0 143 * Build the block left to right.
michael@0 144 * Fill the entire block from Pad to the end with random bytes.
michael@0 145 * Use the bytes after Pad as a supply of extra random bytes from
michael@0 146 * which to find replacements for the zero bytes in Pad.
michael@0 147 * If we need more than that, refill the bytes after Pad with
michael@0 148 * new random bytes as necessary.
michael@0 149 */
michael@0 150 padLen = modulusLen - (data->len + 3);
michael@0 151 PORT_Assert(padLen >= RSA_BLOCK_MIN_PAD_LEN);
michael@0 152 if (padLen < RSA_BLOCK_MIN_PAD_LEN) {
michael@0 153 PORT_Free(block);
michael@0 154 return NULL;
michael@0 155 }
michael@0 156 j = modulusLen - 2;
michael@0 157 rv = RNG_GenerateGlobalRandomBytes(bp, j);
michael@0 158 if (rv == SECSuccess) {
michael@0 159 for (i = 0; i < padLen; ) {
michael@0 160 unsigned char repl;
michael@0 161 /* Pad with non-zero random data. */
michael@0 162 if (bp[i] != RSA_BLOCK_AFTER_PAD_OCTET) {
michael@0 163 ++i;
michael@0 164 continue;
michael@0 165 }
michael@0 166 if (j <= padLen) {
michael@0 167 rv = RNG_GenerateGlobalRandomBytes(bp + padLen,
michael@0 168 modulusLen - (2 + padLen));
michael@0 169 if (rv != SECSuccess)
michael@0 170 break;
michael@0 171 j = modulusLen - 2;
michael@0 172 }
michael@0 173 do {
michael@0 174 repl = bp[--j];
michael@0 175 } while (repl == RSA_BLOCK_AFTER_PAD_OCTET && j > padLen);
michael@0 176 if (repl != RSA_BLOCK_AFTER_PAD_OCTET) {
michael@0 177 bp[i++] = repl;
michael@0 178 }
michael@0 179 }
michael@0 180 }
michael@0 181 if (rv != SECSuccess) {
michael@0 182 PORT_Free(block);
michael@0 183 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
michael@0 184 return NULL;
michael@0 185 }
michael@0 186 bp += padLen;
michael@0 187 *bp++ = RSA_BLOCK_AFTER_PAD_OCTET;
michael@0 188 PORT_Memcpy(bp, data->data, data->len);
michael@0 189 break;
michael@0 190
michael@0 191 default:
michael@0 192 PORT_Assert(0);
michael@0 193 PORT_Free(block);
michael@0 194 return NULL;
michael@0 195 }
michael@0 196
michael@0 197 return block;
michael@0 198 }
michael@0 199
michael@0 200 static SECStatus
michael@0 201 rsa_FormatBlock(SECItem * result,
michael@0 202 unsigned modulusLen,
michael@0 203 RSA_BlockType blockType,
michael@0 204 SECItem * data)
michael@0 205 {
michael@0 206 switch (blockType) {
michael@0 207 case RSA_BlockPrivate:
michael@0 208 case RSA_BlockPublic:
michael@0 209 /*
michael@0 210 * 0x00 || BT || Pad || 0x00 || ActualData
michael@0 211 *
michael@0 212 * The "3" below is the first octet + the second octet + the 0x00
michael@0 213 * octet that always comes just before the ActualData.
michael@0 214 */
michael@0 215 PORT_Assert(data->len <= (modulusLen - (3 + RSA_BLOCK_MIN_PAD_LEN)));
michael@0 216
michael@0 217 result->data = rsa_FormatOneBlock(modulusLen, blockType, data);
michael@0 218 if (result->data == NULL) {
michael@0 219 result->len = 0;
michael@0 220 return SECFailure;
michael@0 221 }
michael@0 222 result->len = modulusLen;
michael@0 223
michael@0 224 break;
michael@0 225
michael@0 226 case RSA_BlockRaw:
michael@0 227 /*
michael@0 228 * Pad || ActualData
michael@0 229 * Pad is zeros. The application is responsible for recovering
michael@0 230 * the actual data.
michael@0 231 */
michael@0 232 if (data->len > modulusLen ) {
michael@0 233 return SECFailure;
michael@0 234 }
michael@0 235 result->data = (unsigned char*)PORT_ZAlloc(modulusLen);
michael@0 236 result->len = modulusLen;
michael@0 237 PORT_Memcpy(result->data + (modulusLen - data->len),
michael@0 238 data->data, data->len);
michael@0 239 break;
michael@0 240
michael@0 241 default:
michael@0 242 PORT_Assert(0);
michael@0 243 result->data = NULL;
michael@0 244 result->len = 0;
michael@0 245 return SECFailure;
michael@0 246 }
michael@0 247
michael@0 248 return SECSuccess;
michael@0 249 }
michael@0 250
michael@0 251 /*
michael@0 252 * Mask generation function MGF1 as defined in PKCS #1 v2.1 / RFC 3447.
michael@0 253 */
michael@0 254 static SECStatus
michael@0 255 MGF1(HASH_HashType hashAlg,
michael@0 256 unsigned char * mask,
michael@0 257 unsigned int maskLen,
michael@0 258 const unsigned char * mgfSeed,
michael@0 259 unsigned int mgfSeedLen)
michael@0 260 {
michael@0 261 unsigned int digestLen;
michael@0 262 PRUint32 counter;
michael@0 263 PRUint32 rounds;
michael@0 264 unsigned char * tempHash;
michael@0 265 unsigned char * temp;
michael@0 266 const SECHashObject * hash;
michael@0 267 void * hashContext;
michael@0 268 unsigned char C[4];
michael@0 269
michael@0 270 hash = HASH_GetRawHashObject(hashAlg);
michael@0 271 if (hash == NULL)
michael@0 272 return SECFailure;
michael@0 273
michael@0 274 hashContext = (*hash->create)();
michael@0 275 rounds = (maskLen + hash->length - 1) / hash->length;
michael@0 276 for (counter = 0; counter < rounds; counter++) {
michael@0 277 C[0] = (unsigned char)((counter >> 24) & 0xff);
michael@0 278 C[1] = (unsigned char)((counter >> 16) & 0xff);
michael@0 279 C[2] = (unsigned char)((counter >> 8) & 0xff);
michael@0 280 C[3] = (unsigned char)(counter & 0xff);
michael@0 281
michael@0 282 /* This could be optimized when the clone functions in
michael@0 283 * rawhash.c are implemented. */
michael@0 284 (*hash->begin)(hashContext);
michael@0 285 (*hash->update)(hashContext, mgfSeed, mgfSeedLen);
michael@0 286 (*hash->update)(hashContext, C, sizeof C);
michael@0 287
michael@0 288 tempHash = mask + counter * hash->length;
michael@0 289 if (counter != (rounds - 1)) {
michael@0 290 (*hash->end)(hashContext, tempHash, &digestLen, hash->length);
michael@0 291 } else { /* we're in the last round and need to cut the hash */
michael@0 292 temp = (unsigned char *)PORT_Alloc(hash->length);
michael@0 293 (*hash->end)(hashContext, temp, &digestLen, hash->length);
michael@0 294 PORT_Memcpy(tempHash, temp, maskLen - counter * hash->length);
michael@0 295 PORT_Free(temp);
michael@0 296 }
michael@0 297 }
michael@0 298 (*hash->destroy)(hashContext, PR_TRUE);
michael@0 299
michael@0 300 return SECSuccess;
michael@0 301 }
michael@0 302
michael@0 303 /* XXX Doesn't set error code */
michael@0 304 SECStatus
michael@0 305 RSA_SignRaw(RSAPrivateKey * key,
michael@0 306 unsigned char * output,
michael@0 307 unsigned int * outputLen,
michael@0 308 unsigned int maxOutputLen,
michael@0 309 const unsigned char * data,
michael@0 310 unsigned int dataLen)
michael@0 311 {
michael@0 312 SECStatus rv = SECSuccess;
michael@0 313 unsigned int modulusLen = rsa_modulusLen(&key->modulus);
michael@0 314 SECItem formatted;
michael@0 315 SECItem unformatted;
michael@0 316
michael@0 317 if (maxOutputLen < modulusLen)
michael@0 318 return SECFailure;
michael@0 319
michael@0 320 unformatted.len = dataLen;
michael@0 321 unformatted.data = (unsigned char*)data;
michael@0 322 formatted.data = NULL;
michael@0 323 rv = rsa_FormatBlock(&formatted, modulusLen, RSA_BlockRaw, &unformatted);
michael@0 324 if (rv != SECSuccess)
michael@0 325 goto done;
michael@0 326
michael@0 327 rv = RSA_PrivateKeyOpDoubleChecked(key, output, formatted.data);
michael@0 328 *outputLen = modulusLen;
michael@0 329
michael@0 330 done:
michael@0 331 if (formatted.data != NULL)
michael@0 332 PORT_ZFree(formatted.data, modulusLen);
michael@0 333 return rv;
michael@0 334 }
michael@0 335
michael@0 336 /* XXX Doesn't set error code */
michael@0 337 SECStatus
michael@0 338 RSA_CheckSignRaw(RSAPublicKey * key,
michael@0 339 const unsigned char * sig,
michael@0 340 unsigned int sigLen,
michael@0 341 const unsigned char * hash,
michael@0 342 unsigned int hashLen)
michael@0 343 {
michael@0 344 SECStatus rv;
michael@0 345 unsigned int modulusLen = rsa_modulusLen(&key->modulus);
michael@0 346 unsigned char * buffer;
michael@0 347
michael@0 348 if (sigLen != modulusLen)
michael@0 349 goto failure;
michael@0 350 if (hashLen > modulusLen)
michael@0 351 goto failure;
michael@0 352
michael@0 353 buffer = (unsigned char *)PORT_Alloc(modulusLen + 1);
michael@0 354 if (!buffer)
michael@0 355 goto failure;
michael@0 356
michael@0 357 rv = RSA_PublicKeyOp(key, buffer, sig);
michael@0 358 if (rv != SECSuccess)
michael@0 359 goto loser;
michael@0 360
michael@0 361 /*
michael@0 362 * make sure we get the same results
michael@0 363 */
michael@0 364 /* XXX(rsleevi): Constant time */
michael@0 365 /* NOTE: should we verify the leading zeros? */
michael@0 366 if (PORT_Memcmp(buffer + (modulusLen - hashLen), hash, hashLen) != 0)
michael@0 367 goto loser;
michael@0 368
michael@0 369 PORT_Free(buffer);
michael@0 370 return SECSuccess;
michael@0 371
michael@0 372 loser:
michael@0 373 PORT_Free(buffer);
michael@0 374 failure:
michael@0 375 return SECFailure;
michael@0 376 }
michael@0 377
michael@0 378 /* XXX Doesn't set error code */
michael@0 379 SECStatus
michael@0 380 RSA_CheckSignRecoverRaw(RSAPublicKey * key,
michael@0 381 unsigned char * data,
michael@0 382 unsigned int * dataLen,
michael@0 383 unsigned int maxDataLen,
michael@0 384 const unsigned char * sig,
michael@0 385 unsigned int sigLen)
michael@0 386 {
michael@0 387 SECStatus rv;
michael@0 388 unsigned int modulusLen = rsa_modulusLen(&key->modulus);
michael@0 389
michael@0 390 if (sigLen != modulusLen)
michael@0 391 goto failure;
michael@0 392 if (maxDataLen < modulusLen)
michael@0 393 goto failure;
michael@0 394
michael@0 395 rv = RSA_PublicKeyOp(key, data, sig);
michael@0 396 if (rv != SECSuccess)
michael@0 397 goto failure;
michael@0 398
michael@0 399 *dataLen = modulusLen;
michael@0 400 return SECSuccess;
michael@0 401
michael@0 402 failure:
michael@0 403 return SECFailure;
michael@0 404 }
michael@0 405
michael@0 406 /* XXX Doesn't set error code */
michael@0 407 SECStatus
michael@0 408 RSA_EncryptRaw(RSAPublicKey * key,
michael@0 409 unsigned char * output,
michael@0 410 unsigned int * outputLen,
michael@0 411 unsigned int maxOutputLen,
michael@0 412 const unsigned char * input,
michael@0 413 unsigned int inputLen)
michael@0 414 {
michael@0 415 SECStatus rv;
michael@0 416 unsigned int modulusLen = rsa_modulusLen(&key->modulus);
michael@0 417 SECItem formatted;
michael@0 418 SECItem unformatted;
michael@0 419
michael@0 420 formatted.data = NULL;
michael@0 421 if (maxOutputLen < modulusLen)
michael@0 422 goto failure;
michael@0 423
michael@0 424 unformatted.len = inputLen;
michael@0 425 unformatted.data = (unsigned char*)input;
michael@0 426 formatted.data = NULL;
michael@0 427 rv = rsa_FormatBlock(&formatted, modulusLen, RSA_BlockRaw, &unformatted);
michael@0 428 if (rv != SECSuccess)
michael@0 429 goto failure;
michael@0 430
michael@0 431 rv = RSA_PublicKeyOp(key, output, formatted.data);
michael@0 432 if (rv != SECSuccess)
michael@0 433 goto failure;
michael@0 434
michael@0 435 PORT_ZFree(formatted.data, modulusLen);
michael@0 436 *outputLen = modulusLen;
michael@0 437 return SECSuccess;
michael@0 438
michael@0 439 failure:
michael@0 440 if (formatted.data != NULL)
michael@0 441 PORT_ZFree(formatted.data, modulusLen);
michael@0 442 return SECFailure;
michael@0 443 }
michael@0 444
michael@0 445 /* XXX Doesn't set error code */
michael@0 446 SECStatus
michael@0 447 RSA_DecryptRaw(RSAPrivateKey * key,
michael@0 448 unsigned char * output,
michael@0 449 unsigned int * outputLen,
michael@0 450 unsigned int maxOutputLen,
michael@0 451 const unsigned char * input,
michael@0 452 unsigned int inputLen)
michael@0 453 {
michael@0 454 SECStatus rv;
michael@0 455 unsigned int modulusLen = rsa_modulusLen(&key->modulus);
michael@0 456
michael@0 457 if (modulusLen > maxOutputLen)
michael@0 458 goto failure;
michael@0 459 if (inputLen != modulusLen)
michael@0 460 goto failure;
michael@0 461
michael@0 462 rv = RSA_PrivateKeyOp(key, output, input);
michael@0 463 if (rv != SECSuccess)
michael@0 464 goto failure;
michael@0 465
michael@0 466 *outputLen = modulusLen;
michael@0 467 return SECSuccess;
michael@0 468
michael@0 469 failure:
michael@0 470 return SECFailure;
michael@0 471 }
michael@0 472
michael@0 473 /*
michael@0 474 * Decodes an EME-OAEP encoded block, validating the encoding in constant
michael@0 475 * time.
michael@0 476 * Described in RFC 3447, section 7.1.2.
michael@0 477 * input contains the encoded block, after decryption.
michael@0 478 * label is the optional value L that was associated with the message.
michael@0 479 * On success, the original message and message length will be stored in
michael@0 480 * output and outputLen.
michael@0 481 */
michael@0 482 static SECStatus
michael@0 483 eme_oaep_decode(unsigned char * output,
michael@0 484 unsigned int * outputLen,
michael@0 485 unsigned int maxOutputLen,
michael@0 486 const unsigned char * input,
michael@0 487 unsigned int inputLen,
michael@0 488 HASH_HashType hashAlg,
michael@0 489 HASH_HashType maskHashAlg,
michael@0 490 const unsigned char * label,
michael@0 491 unsigned int labelLen)
michael@0 492 {
michael@0 493 const SECHashObject * hash;
michael@0 494 void * hashContext;
michael@0 495 SECStatus rv = SECFailure;
michael@0 496 unsigned char labelHash[HASH_LENGTH_MAX];
michael@0 497 unsigned int i;
michael@0 498 unsigned int maskLen;
michael@0 499 unsigned int paddingOffset;
michael@0 500 unsigned char * mask = NULL;
michael@0 501 unsigned char * tmpOutput = NULL;
michael@0 502 unsigned char isGood;
michael@0 503 unsigned char foundPaddingEnd;
michael@0 504
michael@0 505 hash = HASH_GetRawHashObject(hashAlg);
michael@0 506
michael@0 507 /* 1.c */
michael@0 508 if (inputLen < (hash->length * 2) + 2) {
michael@0 509 PORT_SetError(SEC_ERROR_INPUT_LEN);
michael@0 510 return SECFailure;
michael@0 511 }
michael@0 512
michael@0 513 /* Step 3.a - Generate lHash */
michael@0 514 hashContext = (*hash->create)();
michael@0 515 if (hashContext == NULL) {
michael@0 516 PORT_SetError(SEC_ERROR_NO_MEMORY);
michael@0 517 return SECFailure;
michael@0 518 }
michael@0 519 (*hash->begin)(hashContext);
michael@0 520 if (labelLen > 0)
michael@0 521 (*hash->update)(hashContext, label, labelLen);
michael@0 522 (*hash->end)(hashContext, labelHash, &i, sizeof(labelHash));
michael@0 523 (*hash->destroy)(hashContext, PR_TRUE);
michael@0 524
michael@0 525 tmpOutput = (unsigned char*)PORT_Alloc(inputLen);
michael@0 526 if (tmpOutput == NULL) {
michael@0 527 PORT_SetError(SEC_ERROR_NO_MEMORY);
michael@0 528 goto done;
michael@0 529 }
michael@0 530
michael@0 531 maskLen = inputLen - hash->length - 1;
michael@0 532 mask = (unsigned char*)PORT_Alloc(maskLen);
michael@0 533 if (mask == NULL) {
michael@0 534 PORT_SetError(SEC_ERROR_NO_MEMORY);
michael@0 535 goto done;
michael@0 536 }
michael@0 537
michael@0 538 PORT_Memcpy(tmpOutput, input, inputLen);
michael@0 539
michael@0 540 /* 3.c - Generate seedMask */
michael@0 541 MGF1(maskHashAlg, mask, hash->length, &tmpOutput[1 + hash->length],
michael@0 542 inputLen - hash->length - 1);
michael@0 543 /* 3.d - Unmask seed */
michael@0 544 for (i = 0; i < hash->length; ++i)
michael@0 545 tmpOutput[1 + i] ^= mask[i];
michael@0 546
michael@0 547 /* 3.e - Generate dbMask */
michael@0 548 MGF1(maskHashAlg, mask, maskLen, &tmpOutput[1], hash->length);
michael@0 549 /* 3.f - Unmask DB */
michael@0 550 for (i = 0; i < maskLen; ++i)
michael@0 551 tmpOutput[1 + hash->length + i] ^= mask[i];
michael@0 552
michael@0 553 /* 3.g - Compare Y, lHash, and PS in constant time
michael@0 554 * Warning: This code is timing dependent and must not disclose which of
michael@0 555 * these were invalid.
michael@0 556 */
michael@0 557 paddingOffset = 0;
michael@0 558 isGood = 1;
michael@0 559 foundPaddingEnd = 0;
michael@0 560
michael@0 561 /* Compare Y */
michael@0 562 isGood &= constantTimeEQ8(0x00, tmpOutput[0]);
michael@0 563
michael@0 564 /* Compare lHash and lHash' */
michael@0 565 isGood &= constantTimeCompare(&labelHash[0],
michael@0 566 &tmpOutput[1 + hash->length],
michael@0 567 hash->length);
michael@0 568
michael@0 569 /* Compare that the padding is zero or more zero octets, followed by a
michael@0 570 * 0x01 octet */
michael@0 571 for (i = 1 + (hash->length * 2); i < inputLen; ++i) {
michael@0 572 unsigned char isZero = constantTimeEQ8(0x00, tmpOutput[i]);
michael@0 573 unsigned char isOne = constantTimeEQ8(0x01, tmpOutput[i]);
michael@0 574 /* non-constant time equivalent:
michael@0 575 * if (tmpOutput[i] == 0x01 && !foundPaddingEnd)
michael@0 576 * paddingOffset = i;
michael@0 577 */
michael@0 578 paddingOffset = constantTimeCondition(isOne & ~foundPaddingEnd, i,
michael@0 579 paddingOffset);
michael@0 580 /* non-constant time equivalent:
michael@0 581 * if (tmpOutput[i] == 0x01)
michael@0 582 * foundPaddingEnd = true;
michael@0 583 *
michael@0 584 * Note: This may yield false positives, as it will be set whenever
michael@0 585 * a 0x01 byte is encountered. If there was bad padding (eg:
michael@0 586 * 0x03 0x02 0x01), foundPaddingEnd will still be set to true, and
michael@0 587 * paddingOffset will still be set to 2.
michael@0 588 */
michael@0 589 foundPaddingEnd = constantTimeCondition(isOne, 1, foundPaddingEnd);
michael@0 590 /* non-constant time equivalent:
michael@0 591 * if (tmpOutput[i] != 0x00 && tmpOutput[i] != 0x01 &&
michael@0 592 * !foundPaddingEnd) {
michael@0 593 * isGood = false;
michael@0 594 * }
michael@0 595 *
michael@0 596 * Note: This may yield false positives, as a message (and padding)
michael@0 597 * that is entirely zeros will result in isGood still being true. Thus
michael@0 598 * it's necessary to check foundPaddingEnd is positive below.
michael@0 599 */
michael@0 600 isGood = constantTimeCondition(~foundPaddingEnd & ~isZero, 0, isGood);
michael@0 601 }
michael@0 602
michael@0 603 /* While both isGood and foundPaddingEnd may have false positives, they
michael@0 604 * cannot BOTH have false positives. If both are not true, then an invalid
michael@0 605 * message was received. Note, this comparison must still be done in constant
michael@0 606 * time so as not to leak either condition.
michael@0 607 */
michael@0 608 if (!(isGood & foundPaddingEnd)) {
michael@0 609 PORT_SetError(SEC_ERROR_BAD_DATA);
michael@0 610 goto done;
michael@0 611 }
michael@0 612
michael@0 613 /* End timing dependent code */
michael@0 614
michael@0 615 ++paddingOffset; /* Skip the 0x01 following the end of PS */
michael@0 616
michael@0 617 *outputLen = inputLen - paddingOffset;
michael@0 618 if (*outputLen > maxOutputLen) {
michael@0 619 PORT_SetError(SEC_ERROR_OUTPUT_LEN);
michael@0 620 goto done;
michael@0 621 }
michael@0 622
michael@0 623 if (*outputLen)
michael@0 624 PORT_Memcpy(output, &tmpOutput[paddingOffset], *outputLen);
michael@0 625 rv = SECSuccess;
michael@0 626
michael@0 627 done:
michael@0 628 if (mask)
michael@0 629 PORT_ZFree(mask, maskLen);
michael@0 630 if (tmpOutput)
michael@0 631 PORT_ZFree(tmpOutput, inputLen);
michael@0 632 return rv;
michael@0 633 }
michael@0 634
michael@0 635 /*
michael@0 636 * Generate an EME-OAEP encoded block for encryption
michael@0 637 * Described in RFC 3447, section 7.1.1
michael@0 638 * We use input instead of M for the message to be encrypted
michael@0 639 * label is the optional value L to be associated with the message.
michael@0 640 */
michael@0 641 static SECStatus
michael@0 642 eme_oaep_encode(unsigned char * em,
michael@0 643 unsigned int emLen,
michael@0 644 const unsigned char * input,
michael@0 645 unsigned int inputLen,
michael@0 646 HASH_HashType hashAlg,
michael@0 647 HASH_HashType maskHashAlg,
michael@0 648 const unsigned char * label,
michael@0 649 unsigned int labelLen,
michael@0 650 const unsigned char * seed,
michael@0 651 unsigned int seedLen)
michael@0 652 {
michael@0 653 const SECHashObject * hash;
michael@0 654 void * hashContext;
michael@0 655 SECStatus rv;
michael@0 656 unsigned char * mask;
michael@0 657 unsigned int reservedLen;
michael@0 658 unsigned int dbMaskLen;
michael@0 659 unsigned int i;
michael@0 660
michael@0 661 hash = HASH_GetRawHashObject(hashAlg);
michael@0 662 PORT_Assert(seed == NULL || seedLen == hash->length);
michael@0 663
michael@0 664 /* Step 1.b */
michael@0 665 reservedLen = (2 * hash->length) + 2;
michael@0 666 if (emLen < reservedLen || inputLen > (emLen - reservedLen)) {
michael@0 667 PORT_SetError(SEC_ERROR_INPUT_LEN);
michael@0 668 return SECFailure;
michael@0 669 }
michael@0 670
michael@0 671 /*
michael@0 672 * From RFC 3447, Section 7.1
michael@0 673 * +----------+---------+-------+
michael@0 674 * DB = | lHash | PS | M |
michael@0 675 * +----------+---------+-------+
michael@0 676 * |
michael@0 677 * +----------+ V
michael@0 678 * | seed |--> MGF ---> xor
michael@0 679 * +----------+ |
michael@0 680 * | |
michael@0 681 * +--+ V |
michael@0 682 * |00| xor <----- MGF <-----|
michael@0 683 * +--+ | |
michael@0 684 * | | |
michael@0 685 * V V V
michael@0 686 * +--+----------+----------------------------+
michael@0 687 * EM = |00|maskedSeed| maskedDB |
michael@0 688 * +--+----------+----------------------------+
michael@0 689 *
michael@0 690 * We use mask to hold the result of the MGF functions, and all other
michael@0 691 * values are generated in their final resting place.
michael@0 692 */
michael@0 693 *em = 0x00;
michael@0 694
michael@0 695 /* Step 2.a - Generate lHash */
michael@0 696 hashContext = (*hash->create)();
michael@0 697 if (hashContext == NULL) {
michael@0 698 PORT_SetError(SEC_ERROR_NO_MEMORY);
michael@0 699 return SECFailure;
michael@0 700 }
michael@0 701 (*hash->begin)(hashContext);
michael@0 702 if (labelLen > 0)
michael@0 703 (*hash->update)(hashContext, label, labelLen);
michael@0 704 (*hash->end)(hashContext, &em[1 + hash->length], &i, hash->length);
michael@0 705 (*hash->destroy)(hashContext, PR_TRUE);
michael@0 706
michael@0 707 /* Step 2.b - Generate PS */
michael@0 708 if (emLen - reservedLen - inputLen > 0) {
michael@0 709 PORT_Memset(em + 1 + (hash->length * 2), 0x00,
michael@0 710 emLen - reservedLen - inputLen);
michael@0 711 }
michael@0 712
michael@0 713 /* Step 2.c. - Generate DB
michael@0 714 * DB = lHash || PS || 0x01 || M
michael@0 715 * Note that PS and lHash have already been placed into em at their
michael@0 716 * appropriate offsets. This just copies M into place
michael@0 717 */
michael@0 718 em[emLen - inputLen - 1] = 0x01;
michael@0 719 if (inputLen)
michael@0 720 PORT_Memcpy(em + emLen - inputLen, input, inputLen);
michael@0 721
michael@0 722 if (seed == NULL) {
michael@0 723 /* Step 2.d - Generate seed */
michael@0 724 rv = RNG_GenerateGlobalRandomBytes(em + 1, hash->length);
michael@0 725 if (rv != SECSuccess) {
michael@0 726 return rv;
michael@0 727 }
michael@0 728 } else {
michael@0 729 /* For Known Answer Tests, copy the supplied seed. */
michael@0 730 PORT_Memcpy(em + 1, seed, seedLen);
michael@0 731 }
michael@0 732
michael@0 733 /* Step 2.e - Generate dbMask*/
michael@0 734 dbMaskLen = emLen - hash->length - 1;
michael@0 735 mask = (unsigned char*)PORT_Alloc(dbMaskLen);
michael@0 736 if (mask == NULL) {
michael@0 737 PORT_SetError(SEC_ERROR_NO_MEMORY);
michael@0 738 return SECFailure;
michael@0 739 }
michael@0 740 MGF1(maskHashAlg, mask, dbMaskLen, em + 1, hash->length);
michael@0 741 /* Step 2.f - Compute maskedDB*/
michael@0 742 for (i = 0; i < dbMaskLen; ++i)
michael@0 743 em[1 + hash->length + i] ^= mask[i];
michael@0 744
michael@0 745 /* Step 2.g - Generate seedMask */
michael@0 746 MGF1(maskHashAlg, mask, hash->length, &em[1 + hash->length], dbMaskLen);
michael@0 747 /* Step 2.h - Compute maskedSeed */
michael@0 748 for (i = 0; i < hash->length; ++i)
michael@0 749 em[1 + i] ^= mask[i];
michael@0 750
michael@0 751 PORT_ZFree(mask, dbMaskLen);
michael@0 752 return SECSuccess;
michael@0 753 }
michael@0 754
michael@0 755 SECStatus
michael@0 756 RSA_EncryptOAEP(RSAPublicKey * key,
michael@0 757 HASH_HashType hashAlg,
michael@0 758 HASH_HashType maskHashAlg,
michael@0 759 const unsigned char * label,
michael@0 760 unsigned int labelLen,
michael@0 761 const unsigned char * seed,
michael@0 762 unsigned int seedLen,
michael@0 763 unsigned char * output,
michael@0 764 unsigned int * outputLen,
michael@0 765 unsigned int maxOutputLen,
michael@0 766 const unsigned char * input,
michael@0 767 unsigned int inputLen)
michael@0 768 {
michael@0 769 SECStatus rv = SECFailure;
michael@0 770 unsigned int modulusLen = rsa_modulusLen(&key->modulus);
michael@0 771 unsigned char * oaepEncoded = NULL;
michael@0 772
michael@0 773 if (maxOutputLen < modulusLen) {
michael@0 774 PORT_SetError(SEC_ERROR_OUTPUT_LEN);
michael@0 775 return SECFailure;
michael@0 776 }
michael@0 777
michael@0 778 if ((hashAlg == HASH_AlgNULL) || (maskHashAlg == HASH_AlgNULL)) {
michael@0 779 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
michael@0 780 return SECFailure;
michael@0 781 }
michael@0 782
michael@0 783 if ((labelLen == 0 && label != NULL) ||
michael@0 784 (labelLen > 0 && label == NULL)) {
michael@0 785 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
michael@0 786 return SECFailure;
michael@0 787 }
michael@0 788
michael@0 789 oaepEncoded = (unsigned char *)PORT_Alloc(modulusLen);
michael@0 790 if (oaepEncoded == NULL) {
michael@0 791 PORT_SetError(SEC_ERROR_NO_MEMORY);
michael@0 792 return SECFailure;
michael@0 793 }
michael@0 794 rv = eme_oaep_encode(oaepEncoded, modulusLen, input, inputLen,
michael@0 795 hashAlg, maskHashAlg, label, labelLen, seed, seedLen);
michael@0 796 if (rv != SECSuccess)
michael@0 797 goto done;
michael@0 798
michael@0 799 rv = RSA_PublicKeyOp(key, output, oaepEncoded);
michael@0 800 if (rv != SECSuccess)
michael@0 801 goto done;
michael@0 802 *outputLen = modulusLen;
michael@0 803
michael@0 804 done:
michael@0 805 PORT_Free(oaepEncoded);
michael@0 806 return rv;
michael@0 807 }
michael@0 808
michael@0 809 SECStatus
michael@0 810 RSA_DecryptOAEP(RSAPrivateKey * key,
michael@0 811 HASH_HashType hashAlg,
michael@0 812 HASH_HashType maskHashAlg,
michael@0 813 const unsigned char * label,
michael@0 814 unsigned int labelLen,
michael@0 815 unsigned char * output,
michael@0 816 unsigned int * outputLen,
michael@0 817 unsigned int maxOutputLen,
michael@0 818 const unsigned char * input,
michael@0 819 unsigned int inputLen)
michael@0 820 {
michael@0 821 SECStatus rv = SECFailure;
michael@0 822 unsigned int modulusLen = rsa_modulusLen(&key->modulus);
michael@0 823 unsigned char * oaepEncoded = NULL;
michael@0 824
michael@0 825 if ((hashAlg == HASH_AlgNULL) || (maskHashAlg == HASH_AlgNULL)) {
michael@0 826 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
michael@0 827 return SECFailure;
michael@0 828 }
michael@0 829
michael@0 830 if (inputLen != modulusLen) {
michael@0 831 PORT_SetError(SEC_ERROR_INPUT_LEN);
michael@0 832 return SECFailure;
michael@0 833 }
michael@0 834
michael@0 835 if ((labelLen == 0 && label != NULL) ||
michael@0 836 (labelLen > 0 && label == NULL)) {
michael@0 837 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
michael@0 838 return SECFailure;
michael@0 839 }
michael@0 840
michael@0 841 oaepEncoded = (unsigned char *)PORT_Alloc(modulusLen);
michael@0 842 if (oaepEncoded == NULL) {
michael@0 843 PORT_SetError(SEC_ERROR_NO_MEMORY);
michael@0 844 return SECFailure;
michael@0 845 }
michael@0 846
michael@0 847 rv = RSA_PrivateKeyOpDoubleChecked(key, oaepEncoded, input);
michael@0 848 if (rv != SECSuccess) {
michael@0 849 goto done;
michael@0 850 }
michael@0 851 rv = eme_oaep_decode(output, outputLen, maxOutputLen, oaepEncoded,
michael@0 852 modulusLen, hashAlg, maskHashAlg, label,
michael@0 853 labelLen);
michael@0 854
michael@0 855 done:
michael@0 856 if (oaepEncoded)
michael@0 857 PORT_ZFree(oaepEncoded, modulusLen);
michael@0 858 return rv;
michael@0 859 }
michael@0 860
michael@0 861 /* XXX Doesn't set error code */
michael@0 862 SECStatus
michael@0 863 RSA_EncryptBlock(RSAPublicKey * key,
michael@0 864 unsigned char * output,
michael@0 865 unsigned int * outputLen,
michael@0 866 unsigned int maxOutputLen,
michael@0 867 const unsigned char * input,
michael@0 868 unsigned int inputLen)
michael@0 869 {
michael@0 870 SECStatus rv;
michael@0 871 unsigned int modulusLen = rsa_modulusLen(&key->modulus);
michael@0 872 SECItem formatted;
michael@0 873 SECItem unformatted;
michael@0 874
michael@0 875 formatted.data = NULL;
michael@0 876 if (maxOutputLen < modulusLen)
michael@0 877 goto failure;
michael@0 878
michael@0 879 unformatted.len = inputLen;
michael@0 880 unformatted.data = (unsigned char*)input;
michael@0 881 formatted.data = NULL;
michael@0 882 rv = rsa_FormatBlock(&formatted, modulusLen, RSA_BlockPublic,
michael@0 883 &unformatted);
michael@0 884 if (rv != SECSuccess)
michael@0 885 goto failure;
michael@0 886
michael@0 887 rv = RSA_PublicKeyOp(key, output, formatted.data);
michael@0 888 if (rv != SECSuccess)
michael@0 889 goto failure;
michael@0 890
michael@0 891 PORT_ZFree(formatted.data, modulusLen);
michael@0 892 *outputLen = modulusLen;
michael@0 893 return SECSuccess;
michael@0 894
michael@0 895 failure:
michael@0 896 if (formatted.data != NULL)
michael@0 897 PORT_ZFree(formatted.data, modulusLen);
michael@0 898 return SECFailure;
michael@0 899 }
michael@0 900
michael@0 901 /* XXX Doesn't set error code */
michael@0 902 SECStatus
michael@0 903 RSA_DecryptBlock(RSAPrivateKey * key,
michael@0 904 unsigned char * output,
michael@0 905 unsigned int * outputLen,
michael@0 906 unsigned int maxOutputLen,
michael@0 907 const unsigned char * input,
michael@0 908 unsigned int inputLen)
michael@0 909 {
michael@0 910 SECStatus rv;
michael@0 911 unsigned int modulusLen = rsa_modulusLen(&key->modulus);
michael@0 912 unsigned int i;
michael@0 913 unsigned char * buffer;
michael@0 914
michael@0 915 if (inputLen != modulusLen)
michael@0 916 goto failure;
michael@0 917
michael@0 918 buffer = (unsigned char *)PORT_Alloc(modulusLen + 1);
michael@0 919 if (!buffer)
michael@0 920 goto failure;
michael@0 921
michael@0 922 rv = RSA_PrivateKeyOp(key, buffer, input);
michael@0 923 if (rv != SECSuccess)
michael@0 924 goto loser;
michael@0 925
michael@0 926 /* XXX(rsleevi): Constant time */
michael@0 927 if (buffer[0] != RSA_BLOCK_FIRST_OCTET ||
michael@0 928 buffer[1] != (unsigned char)RSA_BlockPublic) {
michael@0 929 goto loser;
michael@0 930 }
michael@0 931 *outputLen = 0;
michael@0 932 for (i = 2; i < modulusLen; i++) {
michael@0 933 if (buffer[i] == RSA_BLOCK_AFTER_PAD_OCTET) {
michael@0 934 *outputLen = modulusLen - i - 1;
michael@0 935 break;
michael@0 936 }
michael@0 937 }
michael@0 938 if (*outputLen == 0)
michael@0 939 goto loser;
michael@0 940 if (*outputLen > maxOutputLen)
michael@0 941 goto loser;
michael@0 942
michael@0 943 PORT_Memcpy(output, buffer + modulusLen - *outputLen, *outputLen);
michael@0 944
michael@0 945 PORT_Free(buffer);
michael@0 946 return SECSuccess;
michael@0 947
michael@0 948 loser:
michael@0 949 PORT_Free(buffer);
michael@0 950 failure:
michael@0 951 return SECFailure;
michael@0 952 }
michael@0 953
michael@0 954 /*
michael@0 955 * Encode a RSA-PSS signature.
michael@0 956 * Described in RFC 3447, section 9.1.1.
michael@0 957 * We use mHash instead of M as input.
michael@0 958 * emBits from the RFC is just modBits - 1, see section 8.1.1.
michael@0 959 * We only support MGF1 as the MGF.
michael@0 960 *
michael@0 961 * NOTE: this code assumes modBits is a multiple of 8.
michael@0 962 */
michael@0 963 static SECStatus
michael@0 964 emsa_pss_encode(unsigned char * em,
michael@0 965 unsigned int emLen,
michael@0 966 const unsigned char * mHash,
michael@0 967 HASH_HashType hashAlg,
michael@0 968 HASH_HashType maskHashAlg,
michael@0 969 const unsigned char * salt,
michael@0 970 unsigned int saltLen)
michael@0 971 {
michael@0 972 const SECHashObject * hash;
michael@0 973 void * hash_context;
michael@0 974 unsigned char * dbMask;
michael@0 975 unsigned int dbMaskLen;
michael@0 976 unsigned int i;
michael@0 977 SECStatus rv;
michael@0 978
michael@0 979 hash = HASH_GetRawHashObject(hashAlg);
michael@0 980 dbMaskLen = emLen - hash->length - 1;
michael@0 981
michael@0 982 /* Step 3 */
michael@0 983 if (emLen < hash->length + saltLen + 2) {
michael@0 984 PORT_SetError(SEC_ERROR_OUTPUT_LEN);
michael@0 985 return SECFailure;
michael@0 986 }
michael@0 987
michael@0 988 /* Step 4 */
michael@0 989 if (salt == NULL) {
michael@0 990 rv = RNG_GenerateGlobalRandomBytes(&em[dbMaskLen - saltLen], saltLen);
michael@0 991 if (rv != SECSuccess) {
michael@0 992 return rv;
michael@0 993 }
michael@0 994 } else {
michael@0 995 PORT_Memcpy(&em[dbMaskLen - saltLen], salt, saltLen);
michael@0 996 }
michael@0 997
michael@0 998 /* Step 5 + 6 */
michael@0 999 /* Compute H and store it at its final location &em[dbMaskLen]. */
michael@0 1000 hash_context = (*hash->create)();
michael@0 1001 if (hash_context == NULL) {
michael@0 1002 PORT_SetError(SEC_ERROR_NO_MEMORY);
michael@0 1003 return SECFailure;
michael@0 1004 }
michael@0 1005 (*hash->begin)(hash_context);
michael@0 1006 (*hash->update)(hash_context, eightZeros, 8);
michael@0 1007 (*hash->update)(hash_context, mHash, hash->length);
michael@0 1008 (*hash->update)(hash_context, &em[dbMaskLen - saltLen], saltLen);
michael@0 1009 (*hash->end)(hash_context, &em[dbMaskLen], &i, hash->length);
michael@0 1010 (*hash->destroy)(hash_context, PR_TRUE);
michael@0 1011
michael@0 1012 /* Step 7 + 8 */
michael@0 1013 PORT_Memset(em, 0, dbMaskLen - saltLen - 1);
michael@0 1014 em[dbMaskLen - saltLen - 1] = 0x01;
michael@0 1015
michael@0 1016 /* Step 9 */
michael@0 1017 dbMask = (unsigned char *)PORT_Alloc(dbMaskLen);
michael@0 1018 if (dbMask == NULL) {
michael@0 1019 PORT_SetError(SEC_ERROR_NO_MEMORY);
michael@0 1020 return SECFailure;
michael@0 1021 }
michael@0 1022 MGF1(maskHashAlg, dbMask, dbMaskLen, &em[dbMaskLen], hash->length);
michael@0 1023
michael@0 1024 /* Step 10 */
michael@0 1025 for (i = 0; i < dbMaskLen; i++)
michael@0 1026 em[i] ^= dbMask[i];
michael@0 1027 PORT_Free(dbMask);
michael@0 1028
michael@0 1029 /* Step 11 */
michael@0 1030 em[0] &= 0x7f;
michael@0 1031
michael@0 1032 /* Step 12 */
michael@0 1033 em[emLen - 1] = 0xbc;
michael@0 1034
michael@0 1035 return SECSuccess;
michael@0 1036 }
michael@0 1037
michael@0 1038 /*
michael@0 1039 * Verify a RSA-PSS signature.
michael@0 1040 * Described in RFC 3447, section 9.1.2.
michael@0 1041 * We use mHash instead of M as input.
michael@0 1042 * emBits from the RFC is just modBits - 1, see section 8.1.2.
michael@0 1043 * We only support MGF1 as the MGF.
michael@0 1044 *
michael@0 1045 * NOTE: this code assumes modBits is a multiple of 8.
michael@0 1046 */
michael@0 1047 static SECStatus
michael@0 1048 emsa_pss_verify(const unsigned char * mHash,
michael@0 1049 const unsigned char * em,
michael@0 1050 unsigned int emLen,
michael@0 1051 HASH_HashType hashAlg,
michael@0 1052 HASH_HashType maskHashAlg,
michael@0 1053 unsigned int saltLen)
michael@0 1054 {
michael@0 1055 const SECHashObject * hash;
michael@0 1056 void * hash_context;
michael@0 1057 unsigned char * db;
michael@0 1058 unsigned char * H_; /* H' from the RFC */
michael@0 1059 unsigned int i;
michael@0 1060 unsigned int dbMaskLen;
michael@0 1061 SECStatus rv;
michael@0 1062
michael@0 1063 hash = HASH_GetRawHashObject(hashAlg);
michael@0 1064 dbMaskLen = emLen - hash->length - 1;
michael@0 1065
michael@0 1066 /* Step 3 + 4 + 6 */
michael@0 1067 if ((emLen < (hash->length + saltLen + 2)) ||
michael@0 1068 (em[emLen - 1] != 0xbc) ||
michael@0 1069 ((em[0] & 0x80) != 0)) {
michael@0 1070 PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
michael@0 1071 return SECFailure;
michael@0 1072 }
michael@0 1073
michael@0 1074 /* Step 7 */
michael@0 1075 db = (unsigned char *)PORT_Alloc(dbMaskLen);
michael@0 1076 if (db == NULL) {
michael@0 1077 PORT_SetError(SEC_ERROR_NO_MEMORY);
michael@0 1078 return SECFailure;
michael@0 1079 }
michael@0 1080 /* &em[dbMaskLen] points to H, used as mgfSeed */
michael@0 1081 MGF1(maskHashAlg, db, dbMaskLen, &em[dbMaskLen], hash->length);
michael@0 1082
michael@0 1083 /* Step 8 */
michael@0 1084 for (i = 0; i < dbMaskLen; i++) {
michael@0 1085 db[i] ^= em[i];
michael@0 1086 }
michael@0 1087
michael@0 1088 /* Step 9 */
michael@0 1089 db[0] &= 0x7f;
michael@0 1090
michael@0 1091 /* Step 10 */
michael@0 1092 for (i = 0; i < (dbMaskLen - saltLen - 1); i++) {
michael@0 1093 if (db[i] != 0) {
michael@0 1094 PORT_Free(db);
michael@0 1095 PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
michael@0 1096 return SECFailure;
michael@0 1097 }
michael@0 1098 }
michael@0 1099 if (db[dbMaskLen - saltLen - 1] != 0x01) {
michael@0 1100 PORT_Free(db);
michael@0 1101 PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
michael@0 1102 return SECFailure;
michael@0 1103 }
michael@0 1104
michael@0 1105 /* Step 12 + 13 */
michael@0 1106 H_ = (unsigned char *)PORT_Alloc(hash->length);
michael@0 1107 if (H_ == NULL) {
michael@0 1108 PORT_Free(db);
michael@0 1109 PORT_SetError(SEC_ERROR_NO_MEMORY);
michael@0 1110 return SECFailure;
michael@0 1111 }
michael@0 1112 hash_context = (*hash->create)();
michael@0 1113 if (hash_context == NULL) {
michael@0 1114 PORT_Free(db);
michael@0 1115 PORT_Free(H_);
michael@0 1116 PORT_SetError(SEC_ERROR_NO_MEMORY);
michael@0 1117 return SECFailure;
michael@0 1118 }
michael@0 1119 (*hash->begin)(hash_context);
michael@0 1120 (*hash->update)(hash_context, eightZeros, 8);
michael@0 1121 (*hash->update)(hash_context, mHash, hash->length);
michael@0 1122 (*hash->update)(hash_context, &db[dbMaskLen - saltLen], saltLen);
michael@0 1123 (*hash->end)(hash_context, H_, &i, hash->length);
michael@0 1124 (*hash->destroy)(hash_context, PR_TRUE);
michael@0 1125
michael@0 1126 PORT_Free(db);
michael@0 1127
michael@0 1128 /* Step 14 */
michael@0 1129 if (PORT_Memcmp(H_, &em[dbMaskLen], hash->length) != 0) {
michael@0 1130 PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
michael@0 1131 rv = SECFailure;
michael@0 1132 } else {
michael@0 1133 rv = SECSuccess;
michael@0 1134 }
michael@0 1135
michael@0 1136 PORT_Free(H_);
michael@0 1137 return rv;
michael@0 1138 }
michael@0 1139
michael@0 1140 SECStatus
michael@0 1141 RSA_SignPSS(RSAPrivateKey * key,
michael@0 1142 HASH_HashType hashAlg,
michael@0 1143 HASH_HashType maskHashAlg,
michael@0 1144 const unsigned char * salt,
michael@0 1145 unsigned int saltLength,
michael@0 1146 unsigned char * output,
michael@0 1147 unsigned int * outputLen,
michael@0 1148 unsigned int maxOutputLen,
michael@0 1149 const unsigned char * input,
michael@0 1150 unsigned int inputLen)
michael@0 1151 {
michael@0 1152 SECStatus rv = SECSuccess;
michael@0 1153 unsigned int modulusLen = rsa_modulusLen(&key->modulus);
michael@0 1154 unsigned char *pssEncoded = NULL;
michael@0 1155
michael@0 1156 if (maxOutputLen < modulusLen) {
michael@0 1157 PORT_SetError(SEC_ERROR_OUTPUT_LEN);
michael@0 1158 return SECFailure;
michael@0 1159 }
michael@0 1160
michael@0 1161 if ((hashAlg == HASH_AlgNULL) || (maskHashAlg == HASH_AlgNULL)) {
michael@0 1162 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
michael@0 1163 return SECFailure;
michael@0 1164 }
michael@0 1165
michael@0 1166 pssEncoded = (unsigned char *)PORT_Alloc(modulusLen);
michael@0 1167 if (pssEncoded == NULL) {
michael@0 1168 PORT_SetError(SEC_ERROR_NO_MEMORY);
michael@0 1169 return SECFailure;
michael@0 1170 }
michael@0 1171 rv = emsa_pss_encode(pssEncoded, modulusLen, input, hashAlg,
michael@0 1172 maskHashAlg, salt, saltLength);
michael@0 1173 if (rv != SECSuccess)
michael@0 1174 goto done;
michael@0 1175
michael@0 1176 rv = RSA_PrivateKeyOpDoubleChecked(key, output, pssEncoded);
michael@0 1177 *outputLen = modulusLen;
michael@0 1178
michael@0 1179 done:
michael@0 1180 PORT_Free(pssEncoded);
michael@0 1181 return rv;
michael@0 1182 }
michael@0 1183
michael@0 1184 SECStatus
michael@0 1185 RSA_CheckSignPSS(RSAPublicKey * key,
michael@0 1186 HASH_HashType hashAlg,
michael@0 1187 HASH_HashType maskHashAlg,
michael@0 1188 unsigned int saltLength,
michael@0 1189 const unsigned char * sig,
michael@0 1190 unsigned int sigLen,
michael@0 1191 const unsigned char * hash,
michael@0 1192 unsigned int hashLen)
michael@0 1193 {
michael@0 1194 SECStatus rv;
michael@0 1195 unsigned int modulusLen = rsa_modulusLen(&key->modulus);
michael@0 1196 unsigned char * buffer;
michael@0 1197
michael@0 1198 if (sigLen != modulusLen) {
michael@0 1199 PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
michael@0 1200 return SECFailure;
michael@0 1201 }
michael@0 1202
michael@0 1203 if ((hashAlg == HASH_AlgNULL) || (maskHashAlg == HASH_AlgNULL)) {
michael@0 1204 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
michael@0 1205 return SECFailure;
michael@0 1206 }
michael@0 1207
michael@0 1208 buffer = (unsigned char *)PORT_Alloc(modulusLen);
michael@0 1209 if (!buffer) {
michael@0 1210 PORT_SetError(SEC_ERROR_NO_MEMORY);
michael@0 1211 return SECFailure;
michael@0 1212 }
michael@0 1213
michael@0 1214 rv = RSA_PublicKeyOp(key, buffer, sig);
michael@0 1215 if (rv != SECSuccess) {
michael@0 1216 PORT_Free(buffer);
michael@0 1217 PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
michael@0 1218 return SECFailure;
michael@0 1219 }
michael@0 1220
michael@0 1221 rv = emsa_pss_verify(hash, buffer, modulusLen, hashAlg,
michael@0 1222 maskHashAlg, saltLength);
michael@0 1223 PORT_Free(buffer);
michael@0 1224
michael@0 1225 return rv;
michael@0 1226 }
michael@0 1227
michael@0 1228 /* XXX Doesn't set error code */
michael@0 1229 SECStatus
michael@0 1230 RSA_Sign(RSAPrivateKey * key,
michael@0 1231 unsigned char * output,
michael@0 1232 unsigned int * outputLen,
michael@0 1233 unsigned int maxOutputLen,
michael@0 1234 const unsigned char * input,
michael@0 1235 unsigned int inputLen)
michael@0 1236 {
michael@0 1237 SECStatus rv = SECSuccess;
michael@0 1238 unsigned int modulusLen = rsa_modulusLen(&key->modulus);
michael@0 1239 SECItem formatted;
michael@0 1240 SECItem unformatted;
michael@0 1241
michael@0 1242 if (maxOutputLen < modulusLen)
michael@0 1243 return SECFailure;
michael@0 1244
michael@0 1245 unformatted.len = inputLen;
michael@0 1246 unformatted.data = (unsigned char*)input;
michael@0 1247 formatted.data = NULL;
michael@0 1248 rv = rsa_FormatBlock(&formatted, modulusLen, RSA_BlockPrivate,
michael@0 1249 &unformatted);
michael@0 1250 if (rv != SECSuccess)
michael@0 1251 goto done;
michael@0 1252
michael@0 1253 rv = RSA_PrivateKeyOpDoubleChecked(key, output, formatted.data);
michael@0 1254 *outputLen = modulusLen;
michael@0 1255
michael@0 1256 goto done;
michael@0 1257
michael@0 1258 done:
michael@0 1259 if (formatted.data != NULL)
michael@0 1260 PORT_ZFree(formatted.data, modulusLen);
michael@0 1261 return rv;
michael@0 1262 }
michael@0 1263
michael@0 1264 /* XXX Doesn't set error code */
michael@0 1265 SECStatus
michael@0 1266 RSA_CheckSign(RSAPublicKey * key,
michael@0 1267 const unsigned char * sig,
michael@0 1268 unsigned int sigLen,
michael@0 1269 const unsigned char * data,
michael@0 1270 unsigned int dataLen)
michael@0 1271 {
michael@0 1272 SECStatus rv;
michael@0 1273 unsigned int modulusLen = rsa_modulusLen(&key->modulus);
michael@0 1274 unsigned int i;
michael@0 1275 unsigned char * buffer;
michael@0 1276
michael@0 1277 if (sigLen != modulusLen)
michael@0 1278 goto failure;
michael@0 1279 /*
michael@0 1280 * 0x00 || BT || Pad || 0x00 || ActualData
michael@0 1281 *
michael@0 1282 * The "3" below is the first octet + the second octet + the 0x00
michael@0 1283 * octet that always comes just before the ActualData.
michael@0 1284 */
michael@0 1285 if (dataLen > modulusLen - (3 + RSA_BLOCK_MIN_PAD_LEN))
michael@0 1286 goto failure;
michael@0 1287
michael@0 1288 buffer = (unsigned char *)PORT_Alloc(modulusLen + 1);
michael@0 1289 if (!buffer)
michael@0 1290 goto failure;
michael@0 1291
michael@0 1292 rv = RSA_PublicKeyOp(key, buffer, sig);
michael@0 1293 if (rv != SECSuccess)
michael@0 1294 goto loser;
michael@0 1295
michael@0 1296 /*
michael@0 1297 * check the padding that was used
michael@0 1298 */
michael@0 1299 if (buffer[0] != RSA_BLOCK_FIRST_OCTET ||
michael@0 1300 buffer[1] != (unsigned char)RSA_BlockPrivate) {
michael@0 1301 goto loser;
michael@0 1302 }
michael@0 1303 for (i = 2; i < modulusLen - dataLen - 1; i++) {
michael@0 1304 if (buffer[i] != RSA_BLOCK_PRIVATE_PAD_OCTET)
michael@0 1305 goto loser;
michael@0 1306 }
michael@0 1307 if (buffer[i] != RSA_BLOCK_AFTER_PAD_OCTET)
michael@0 1308 goto loser;
michael@0 1309
michael@0 1310 /*
michael@0 1311 * make sure we get the same results
michael@0 1312 */
michael@0 1313 if (PORT_Memcmp(buffer + modulusLen - dataLen, data, dataLen) != 0)
michael@0 1314 goto loser;
michael@0 1315
michael@0 1316 PORT_Free(buffer);
michael@0 1317 return SECSuccess;
michael@0 1318
michael@0 1319 loser:
michael@0 1320 PORT_Free(buffer);
michael@0 1321 failure:
michael@0 1322 return SECFailure;
michael@0 1323 }
michael@0 1324
michael@0 1325 /* XXX Doesn't set error code */
michael@0 1326 SECStatus
michael@0 1327 RSA_CheckSignRecover(RSAPublicKey * key,
michael@0 1328 unsigned char * output,
michael@0 1329 unsigned int * outputLen,
michael@0 1330 unsigned int maxOutputLen,
michael@0 1331 const unsigned char * sig,
michael@0 1332 unsigned int sigLen)
michael@0 1333 {
michael@0 1334 SECStatus rv;
michael@0 1335 unsigned int modulusLen = rsa_modulusLen(&key->modulus);
michael@0 1336 unsigned int i;
michael@0 1337 unsigned char * buffer;
michael@0 1338
michael@0 1339 if (sigLen != modulusLen)
michael@0 1340 goto failure;
michael@0 1341
michael@0 1342 buffer = (unsigned char *)PORT_Alloc(modulusLen + 1);
michael@0 1343 if (!buffer)
michael@0 1344 goto failure;
michael@0 1345
michael@0 1346 rv = RSA_PublicKeyOp(key, buffer, sig);
michael@0 1347 if (rv != SECSuccess)
michael@0 1348 goto loser;
michael@0 1349 *outputLen = 0;
michael@0 1350
michael@0 1351 /*
michael@0 1352 * check the padding that was used
michael@0 1353 */
michael@0 1354 if (buffer[0] != RSA_BLOCK_FIRST_OCTET ||
michael@0 1355 buffer[1] != (unsigned char)RSA_BlockPrivate) {
michael@0 1356 goto loser;
michael@0 1357 }
michael@0 1358 for (i = 2; i < modulusLen; i++) {
michael@0 1359 if (buffer[i] == RSA_BLOCK_AFTER_PAD_OCTET) {
michael@0 1360 *outputLen = modulusLen - i - 1;
michael@0 1361 break;
michael@0 1362 }
michael@0 1363 if (buffer[i] != RSA_BLOCK_PRIVATE_PAD_OCTET)
michael@0 1364 goto loser;
michael@0 1365 }
michael@0 1366 if (*outputLen == 0)
michael@0 1367 goto loser;
michael@0 1368 if (*outputLen > maxOutputLen)
michael@0 1369 goto loser;
michael@0 1370
michael@0 1371 PORT_Memcpy(output, buffer + modulusLen - *outputLen, *outputLen);
michael@0 1372
michael@0 1373 PORT_Free(buffer);
michael@0 1374 return SECSuccess;
michael@0 1375
michael@0 1376 loser:
michael@0 1377 PORT_Free(buffer);
michael@0 1378 failure:
michael@0 1379 return SECFailure;
michael@0 1380 }

mercurial