1eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch/* 2eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * PKCS#1 encoding and decoding functions. 3eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * This file is believed to contain no code licensed from other parties. 4eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * 5eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * This Source Code Form is subject to the terms of the Mozilla Public 6eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * License, v. 2.0. If a copy of the MPL was not distributed with this 7eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 8eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 9eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "seccomon.h" 10eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "secerr.h" 11eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "sechash.h" 12eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 13eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch/* Needed for RSA-PSS functions */ 14eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic const unsigned char eightZeros[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; 15eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 16eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch/* 17eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * Mask generation function MGF1 as defined in PKCS #1 v2.1 / RFC 3447. 18eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch */ 19eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic SECStatus 20eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochMGF1(HASH_HashType hashAlg, unsigned char *mask, unsigned int maskLen, 21eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const unsigned char *mgfSeed, unsigned int mgfSeedLen) 22eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch{ 23eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch unsigned int digestLen; 24eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch PRUint32 counter, rounds; 25eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch unsigned char *tempHash, *temp; 26eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const SECHashObject *hash; 27eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch void *hashContext; 28eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch unsigned char C[4]; 29eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 30eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch hash = HASH_GetHashObject(hashAlg); 31eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (hash == NULL) 32eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return SECFailure; 33eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 34eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch hashContext = (*hash->create)(); 35eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch rounds = (maskLen + hash->length - 1) / hash->length; 36eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch for (counter = 0; counter < rounds; counter++) { 37eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch C[0] = (unsigned char)((counter >> 24) & 0xff); 38eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch C[1] = (unsigned char)((counter >> 16) & 0xff); 39eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch C[2] = (unsigned char)((counter >> 8) & 0xff); 40eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch C[3] = (unsigned char)(counter & 0xff); 41eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 42eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch /* This could be optimized when the clone functions in 43eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * rawhash.c are implemented. */ 44eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch (*hash->begin)(hashContext); 45eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch (*hash->update)(hashContext, mgfSeed, mgfSeedLen); 46eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch (*hash->update)(hashContext, C, sizeof C); 47eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 48eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch tempHash = mask + counter * hash->length; 49eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (counter != (rounds-1)) { 50eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch (*hash->end)(hashContext, tempHash, &digestLen, hash->length); 51eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } else { /* we're in the last round and need to cut the hash */ 52eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch temp = (unsigned char *)PORT_Alloc(hash->length); 53eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch (*hash->end)(hashContext, temp, &digestLen, hash->length); 54eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch PORT_Memcpy(tempHash, temp, maskLen - counter * hash->length); 55eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch PORT_Free(temp); 56eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 57eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 58eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch (*hash->destroy)(hashContext, PR_TRUE); 59eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 60eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return SECSuccess; 61eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 62eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 63eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch/* 64eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * Verify a RSA-PSS signature. 65eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * Described in RFC 3447, section 9.1.2. 66eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * We use mHash instead of M as input. 67eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * emBits from the RFC is just modBits - 1, see section 8.1.2. 68eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * We only support MGF1 as the MGF. 69eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * 70eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * NOTE: this code assumes modBits is a multiple of 8. 71eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch */ 72eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochSECStatus 73eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochemsa_pss_verify(const unsigned char *mHash, 74eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const unsigned char *em, unsigned int emLen, 75eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch HASH_HashType hashAlg, HASH_HashType maskHashAlg, 76eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch unsigned int sLen) 77eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch{ 78eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const SECHashObject *hash; 79eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch void *hash_context; 80eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch unsigned char *db; 81eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch unsigned char *H_; /* H' from the RFC */ 82eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch unsigned int i, dbMaskLen; 83eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch SECStatus rv; 84eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 85eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch hash = HASH_GetHashObject(hashAlg); 86eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch dbMaskLen = emLen - hash->length - 1; 87eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 88eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch /* Step 3 + 4 + 6 */ 89eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if ((emLen < (hash->length + sLen + 2)) || 90eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch (em[emLen - 1] != 0xbc) || 91eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ((em[0] & 0x80) != 0)) { 92eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch PORT_SetError(SEC_ERROR_BAD_SIGNATURE); 93eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return SECFailure; 94eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 95eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 96eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch /* Step 7 */ 97eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch db = (unsigned char *)PORT_Alloc(dbMaskLen); 98eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (db == NULL) { 99eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch PORT_SetError(SEC_ERROR_NO_MEMORY); 100eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return SECFailure; 101eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 102eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch /* &em[dbMaskLen] points to H, used as mgfSeed */ 103eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch MGF1(maskHashAlg, db, dbMaskLen, &em[dbMaskLen], hash->length); 104eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 105eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch /* Step 8 */ 106eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch for (i = 0; i < dbMaskLen; i++) { 107eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch db[i] ^= em[i]; 108eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 109eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 110eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch /* Step 9 */ 111eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch db[0] &= 0x7f; 112eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 113eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch /* Step 10 */ 114eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch for (i = 0; i < (dbMaskLen - sLen - 1); i++) { 115eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (db[i] != 0) { 116eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch PORT_Free(db); 117eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch PORT_SetError(SEC_ERROR_BAD_SIGNATURE); 118eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return SECFailure; 119eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 120eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 121eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (db[dbMaskLen - sLen - 1] != 0x01) { 122eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch PORT_Free(db); 123eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch PORT_SetError(SEC_ERROR_BAD_SIGNATURE); 124eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return SECFailure; 125eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 126eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 127eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch /* Step 12 + 13 */ 128eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch H_ = (unsigned char *)PORT_Alloc(hash->length); 129eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (H_ == NULL) { 130eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch PORT_Free(db); 131eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch PORT_SetError(SEC_ERROR_NO_MEMORY); 132eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return SECFailure; 133eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 134eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch hash_context = (*hash->create)(); 135eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (hash_context == NULL) { 136eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch PORT_Free(db); 137eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch PORT_Free(H_); 138eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch PORT_SetError(SEC_ERROR_NO_MEMORY); 139eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return SECFailure; 140eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 141eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch (*hash->begin)(hash_context); 142eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch (*hash->update)(hash_context, eightZeros, 8); 143eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch (*hash->update)(hash_context, mHash, hash->length); 144eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch (*hash->update)(hash_context, &db[dbMaskLen - sLen], sLen); 145eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch (*hash->end)(hash_context, H_, &i, hash->length); 146eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch (*hash->destroy)(hash_context, PR_TRUE); 147eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 148eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch PORT_Free(db); 149eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 150eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch /* Step 14 */ 151eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (PORT_Memcmp(H_, &em[dbMaskLen], hash->length) != 0) { 152eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch PORT_SetError(SEC_ERROR_BAD_SIGNATURE); 153eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch rv = SECFailure; 154eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } else { 155eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch rv = SECSuccess; 156eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 157eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 158eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch PORT_Free(H_); 159eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return rv; 160eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 161