From 7044d328a239ee63126280dce485a497cbe5c2a8 Mon Sep 17 00:00:00 2001 From: "Dr. Stephen Henson" Date: Fri, 27 May 2005 21:59:52 +0000 Subject: [PATCH] Add PSS support. Minimal at this stage for FIPS140. --- crypto/rsa/Makefile | 4 +- crypto/rsa/rsa.h | 14 +++ crypto/rsa/rsa_err.c | 6 ++ crypto/rsa/rsa_oaep.c | 32 +++--- crypto/rsa/rsa_pss.c | 220 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 261 insertions(+), 15 deletions(-) create mode 100644 crypto/rsa/rsa_pss.c diff --git a/crypto/rsa/Makefile b/crypto/rsa/Makefile index 5748b0d3d0..f69e54771e 100644 --- a/crypto/rsa/Makefile +++ b/crypto/rsa/Makefile @@ -24,10 +24,10 @@ APPS= LIB=$(TOP)/libcrypto.a LIBSRC= rsa_eay.c rsa_gen.c rsa_lib.c rsa_sign.c rsa_saos.c rsa_err.c \ rsa_pk1.c rsa_ssl.c rsa_none.c rsa_oaep.c rsa_chk.c rsa_null.c \ - rsa_asn1.c + rsa_pss.c rsa_asn1.c LIBOBJ= rsa_eay.o rsa_gen.o rsa_lib.o rsa_sign.o rsa_saos.o rsa_err.o \ rsa_pk1.o rsa_ssl.o rsa_none.o rsa_oaep.o rsa_chk.o rsa_null.o \ - rsa_asn1.o + rsa_pss.o rsa_asn1.o SRC= $(LIBSRC) diff --git a/crypto/rsa/rsa.h b/crypto/rsa/rsa.h index d18c17ff8b..cc7107b30e 100644 --- a/crypto/rsa/rsa.h +++ b/crypto/rsa/rsa.h @@ -275,6 +275,8 @@ int RSA_padding_add_PKCS1_type_2(unsigned char *to,int tlen, const unsigned char *f,int fl); int RSA_padding_check_PKCS1_type_2(unsigned char *to,int tlen, const unsigned char *f,int fl,int rsa_len); +int PKCS1_MGF1(unsigned char *mask, long len, + const unsigned char *seed, long seedlen, const EVP_MD *dgst); int RSA_padding_add_PKCS1_OAEP(unsigned char *to,int tlen, const unsigned char *f,int fl, const unsigned char *p,int pl); @@ -290,6 +292,12 @@ int RSA_padding_add_none(unsigned char *to,int tlen, int RSA_padding_check_none(unsigned char *to,int tlen, const unsigned char *f,int fl,int rsa_len); +int RSA_verify_PKCS1_PSS(RSA *rsa, const unsigned char *mHash, + const EVP_MD *Hash, const unsigned char *EM, int sLen); +int RSA_padding_add_PKCS1_PSS(RSA *rsa, unsigned char *EM, + const unsigned char *mHash, + const EVP_MD *Hash, int sLen); + int RSA_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func); int RSA_set_ex_data(RSA *r,int idx,void *arg); @@ -318,6 +326,7 @@ void ERR_load_RSA_strings(void); #define RSA_F_RSA_NULL 124 #define RSA_F_RSA_PADDING_ADD_NONE 107 #define RSA_F_RSA_PADDING_ADD_PKCS1_OAEP 121 +#define RSA_F_RSA_PADDING_ADD_PKCS1_PSS 125 #define RSA_F_RSA_PADDING_ADD_PKCS1_TYPE_1 108 #define RSA_F_RSA_PADDING_ADD_PKCS1_TYPE_2 109 #define RSA_F_RSA_PADDING_ADD_SSLV23 110 @@ -332,6 +341,7 @@ void ERR_load_RSA_strings(void); #define RSA_F_RSA_SIGN_ASN1_OCTET_STRING 118 #define RSA_F_RSA_VERIFY 119 #define RSA_F_RSA_VERIFY_ASN1_OCTET_STRING 120 +#define RSA_F_RSA_VERIFY_PKCS1_PSS 126 /* Reason codes. */ #define RSA_R_ALGORITHM_MISMATCH 100 @@ -351,12 +361,15 @@ void ERR_load_RSA_strings(void); #define RSA_R_DMP1_NOT_CONGRUENT_TO_D 124 #define RSA_R_DMQ1_NOT_CONGRUENT_TO_D 125 #define RSA_R_D_E_NOT_CONGRUENT_TO_1 123 +#define RSA_R_FIRST_OCTET_INVALID 133 #define RSA_R_INVALID_MESSAGE_LENGTH 131 #define RSA_R_IQMP_NOT_INVERSE_OF_Q 126 #define RSA_R_KEY_SIZE_TOO_SMALL 120 +#define RSA_R_LAST_OCTET_INVALID 134 #define RSA_R_NULL_BEFORE_BLOCK_MISSING 113 #define RSA_R_N_DOES_NOT_EQUAL_P_Q 127 #define RSA_R_OAEP_DECODING_ERROR 121 +#define RSA_R_ONE_CHECK_FAILED 135 #define RSA_R_PADDING_CHECK_FAILED 114 #define RSA_R_P_NOT_PRIME 128 #define RSA_R_Q_NOT_PRIME 129 @@ -366,6 +379,7 @@ void ERR_load_RSA_strings(void); #define RSA_R_UNKNOWN_ALGORITHM_TYPE 117 #define RSA_R_UNKNOWN_PADDING_TYPE 118 #define RSA_R_WRONG_SIGNATURE_LENGTH 119 +#define RSA_R_ZERO_CHECK_FAILED 136 #ifdef __cplusplus } diff --git a/crypto/rsa/rsa_err.c b/crypto/rsa/rsa_err.c index 07ef9df0cd..8cbbd05db3 100644 --- a/crypto/rsa/rsa_err.c +++ b/crypto/rsa/rsa_err.c @@ -81,6 +81,7 @@ static ERR_STRING_DATA RSA_str_functs[]= {ERR_FUNC(RSA_F_RSA_NULL), "RSA_NULL"}, {ERR_FUNC(RSA_F_RSA_PADDING_ADD_NONE), "RSA_padding_add_none"}, {ERR_FUNC(RSA_F_RSA_PADDING_ADD_PKCS1_OAEP), "RSA_padding_add_PKCS1_OAEP"}, +{ERR_FUNC(RSA_F_RSA_PADDING_ADD_PKCS1_PSS), "RSA_padding_add_PKCS1_PSS"}, {ERR_FUNC(RSA_F_RSA_PADDING_ADD_PKCS1_TYPE_1), "RSA_padding_add_PKCS1_type_1"}, {ERR_FUNC(RSA_F_RSA_PADDING_ADD_PKCS1_TYPE_2), "RSA_padding_add_PKCS1_type_2"}, {ERR_FUNC(RSA_F_RSA_PADDING_ADD_SSLV23), "RSA_padding_add_SSLv23"}, @@ -95,6 +96,7 @@ static ERR_STRING_DATA RSA_str_functs[]= {ERR_FUNC(RSA_F_RSA_SIGN_ASN1_OCTET_STRING), "RSA_sign_ASN1_OCTET_STRING"}, {ERR_FUNC(RSA_F_RSA_VERIFY), "RSA_verify"}, {ERR_FUNC(RSA_F_RSA_VERIFY_ASN1_OCTET_STRING), "RSA_verify_ASN1_OCTET_STRING"}, +{ERR_FUNC(RSA_F_RSA_VERIFY_PKCS1_PSS), "RSA_verify_PKCS1_PSS"}, {0,NULL} }; @@ -117,12 +119,15 @@ static ERR_STRING_DATA RSA_str_reasons[]= {ERR_REASON(RSA_R_DMP1_NOT_CONGRUENT_TO_D),"dmp1 not congruent to d"}, {ERR_REASON(RSA_R_DMQ1_NOT_CONGRUENT_TO_D),"dmq1 not congruent to d"}, {ERR_REASON(RSA_R_D_E_NOT_CONGRUENT_TO_1),"d e not congruent to 1"}, +{ERR_REASON(RSA_R_FIRST_OCTET_INVALID) ,"first octet invalid"}, {ERR_REASON(RSA_R_INVALID_MESSAGE_LENGTH),"invalid message length"}, {ERR_REASON(RSA_R_IQMP_NOT_INVERSE_OF_Q) ,"iqmp not inverse of q"}, {ERR_REASON(RSA_R_KEY_SIZE_TOO_SMALL) ,"key size too small"}, +{ERR_REASON(RSA_R_LAST_OCTET_INVALID) ,"last octet invalid"}, {ERR_REASON(RSA_R_NULL_BEFORE_BLOCK_MISSING),"null before block missing"}, {ERR_REASON(RSA_R_N_DOES_NOT_EQUAL_P_Q) ,"n does not equal p q"}, {ERR_REASON(RSA_R_OAEP_DECODING_ERROR) ,"oaep decoding error"}, +{ERR_REASON(RSA_R_ONE_CHECK_FAILED) ,"one check failed"}, {ERR_REASON(RSA_R_PADDING_CHECK_FAILED) ,"padding check failed"}, {ERR_REASON(RSA_R_P_NOT_PRIME) ,"p not prime"}, {ERR_REASON(RSA_R_Q_NOT_PRIME) ,"q not prime"}, @@ -132,6 +137,7 @@ static ERR_STRING_DATA RSA_str_reasons[]= {ERR_REASON(RSA_R_UNKNOWN_ALGORITHM_TYPE),"unknown algorithm type"}, {ERR_REASON(RSA_R_UNKNOWN_PADDING_TYPE) ,"unknown padding type"}, {ERR_REASON(RSA_R_WRONG_SIGNATURE_LENGTH),"wrong signature length"}, +{ERR_REASON(RSA_R_ZERO_CHECK_FAILED) ,"zero check failed"}, {0,NULL} }; diff --git a/crypto/rsa/rsa_oaep.c b/crypto/rsa/rsa_oaep.c index e3f7c608ec..d43ecaca63 100644 --- a/crypto/rsa/rsa_oaep.c +++ b/crypto/rsa/rsa_oaep.c @@ -28,9 +28,6 @@ #include #include -int MGF1(unsigned char *mask, long len, - const unsigned char *seed, long seedlen); - int RSA_padding_add_PKCS1_OAEP(unsigned char *to, int tlen, const unsigned char *from, int flen, const unsigned char *param, int plen) @@ -76,11 +73,13 @@ int RSA_padding_add_PKCS1_OAEP(unsigned char *to, int tlen, 20); #endif - MGF1(dbmask, emlen - SHA_DIGEST_LENGTH, seed, SHA_DIGEST_LENGTH); + PKCS1_MGF1(dbmask, emlen - SHA_DIGEST_LENGTH, seed, SHA_DIGEST_LENGTH, + EVP_sha1()); for (i = 0; i < emlen - SHA_DIGEST_LENGTH; i++) db[i] ^= dbmask[i]; - MGF1(seedmask, SHA_DIGEST_LENGTH, db, emlen - SHA_DIGEST_LENGTH); + PKCS1_MGF1(seedmask, SHA_DIGEST_LENGTH, db, emlen - SHA_DIGEST_LENGTH, + EVP_sha1()); for (i = 0; i < SHA_DIGEST_LENGTH; i++) seed[i] ^= seedmask[i]; @@ -126,11 +125,11 @@ int RSA_padding_check_PKCS1_OAEP(unsigned char *to, int tlen, return -1; } - MGF1(seed, SHA_DIGEST_LENGTH, maskeddb, dblen); + PKCS1_MGF1(seed, SHA_DIGEST_LENGTH, maskeddb, dblen, EVP_sha1()); for (i = lzero; i < SHA_DIGEST_LENGTH; i++) seed[i] ^= from[i - lzero]; - MGF1(db, dblen, seed, SHA_DIGEST_LENGTH); + PKCS1_MGF1(db, dblen, seed, SHA_DIGEST_LENGTH, EVP_sha1()); for (i = 0; i < dblen; i++) db[i] ^= maskeddb[i]; @@ -170,28 +169,30 @@ decoding_err: return -1; } -int MGF1(unsigned char *mask, long len, - const unsigned char *seed, long seedlen) +int PKCS1_MGF1(unsigned char *mask, long len, + const unsigned char *seed, long seedlen, const EVP_MD *dgst) { long i, outlen = 0; unsigned char cnt[4]; EVP_MD_CTX c; - unsigned char md[SHA_DIGEST_LENGTH]; + unsigned char md[EVP_MAX_MD_SIZE]; + int mdlen; EVP_MD_CTX_init(&c); + mdlen = EVP_MD_size(dgst); for (i = 0; outlen < len; i++) { cnt[0] = (unsigned char)((i >> 24) & 255); cnt[1] = (unsigned char)((i >> 16) & 255); cnt[2] = (unsigned char)((i >> 8)) & 255; cnt[3] = (unsigned char)(i & 255); - EVP_DigestInit_ex(&c,EVP_sha1(), NULL); + EVP_DigestInit_ex(&c,dgst, NULL); EVP_DigestUpdate(&c, seed, seedlen); EVP_DigestUpdate(&c, cnt, 4); - if (outlen + SHA_DIGEST_LENGTH <= len) + if (outlen + mdlen <= len) { EVP_DigestFinal_ex(&c, mask + outlen, NULL); - outlen += SHA_DIGEST_LENGTH; + outlen += mdlen; } else { @@ -203,4 +204,9 @@ int MGF1(unsigned char *mask, long len, EVP_MD_CTX_cleanup(&c); return 0; } + +int MGF1(unsigned char *mask, long len, const unsigned char *seed, long seedlen) + { + return PKCS1_MGF1(mask, len, seed, seedlen, EVP_sha1()); + } #endif diff --git a/crypto/rsa/rsa_pss.c b/crypto/rsa/rsa_pss.c new file mode 100644 index 0000000000..a47035733d --- /dev/null +++ b/crypto/rsa/rsa_pss.c @@ -0,0 +1,220 @@ +/* rsa_pss.c */ +/* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL + * project 2005. + */ +/* ==================================================================== + * Copyright (c) 2005 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#include +#include "cryptlib.h" +#include +#include +#include +#include +#include + +const static unsigned char zeroes[] = {0,0,0,0,0,0,0,0}; + +int RSA_verify_PKCS1_PSS(RSA *rsa, const unsigned char *mHash, + const EVP_MD *Hash, const unsigned char *EM, int sLen) + { + int i; + int ret = 0; + int hLen, maskedDBLen, emBits, emLen; + const unsigned char *H; + unsigned char *DB = NULL; + EVP_MD_CTX ctx; + unsigned char H_[EVP_MAX_MD_SIZE]; + emBits = BN_num_bits(rsa->n) - 1; + emLen = (emBits + 7) >> 3; + hLen = EVP_MD_size(Hash); + if (emLen < (hLen + sLen + 2)) + { + RSAerr(RSA_F_RSA_VERIFY_PKCS1_PSS, RSA_R_DATA_TOO_LARGE); + goto err; + } + if (EM[emLen - 1] != 0xbc) + { + RSAerr(RSA_F_RSA_VERIFY_PKCS1_PSS, RSA_R_LAST_OCTET_INVALID); + goto err; + } + if (EM[0] & (0xFF << (emBits & 0x7))) + { + RSAerr(RSA_F_RSA_VERIFY_PKCS1_PSS, RSA_R_FIRST_OCTET_INVALID); + goto err; + } + maskedDBLen = emLen - hLen - 1; + H = EM + maskedDBLen; + DB = OPENSSL_malloc(maskedDBLen); + if (!DB) + { + RSAerr(RSA_F_RSA_VERIFY_PKCS1_PSS, ERR_R_MALLOC_FAILURE); + goto err; + } + PKCS1_MGF1(DB, maskedDBLen, H, hLen, Hash); + for (i = 0; i < maskedDBLen; i++) + DB[i] ^= EM[i]; + DB[0] &= 0xFF >> (8 - (emBits & 0x7)); + for (i = 0; i < (emLen - hLen - sLen - 2); i++) + { + if (DB[i] != 0) + { + RSAerr(RSA_F_RSA_VERIFY_PKCS1_PSS, + RSA_R_ZERO_CHECK_FAILED); + goto err; + } + } + if (DB[i] != 0x1) + { + RSAerr(RSA_F_RSA_VERIFY_PKCS1_PSS, RSA_R_ONE_CHECK_FAILED); + goto err; + } + EVP_MD_CTX_init(&ctx); + EVP_DigestInit_ex(&ctx, Hash, NULL); + EVP_DigestUpdate(&ctx, zeroes, sizeof zeroes); + EVP_DigestUpdate(&ctx, mHash, hLen); + if (sLen) + EVP_DigestUpdate(&ctx, DB + maskedDBLen - sLen, sLen); + EVP_DigestFinal(&ctx, H_, NULL); + EVP_MD_CTX_cleanup(&ctx); + if (memcmp(H_, H, hLen)) + { + RSAerr(RSA_F_RSA_VERIFY_PKCS1_PSS, RSA_R_BAD_SIGNATURE); + ret = 0; + } + else + ret = 1; + + err: + if (DB) + OPENSSL_free(DB); + + return ret; + + } + +int RSA_padding_add_PKCS1_PSS(RSA *rsa, unsigned char *EM, + const unsigned char *mHash, + const EVP_MD *Hash, int sLen) + { + int i; + int ret = 0; + int hLen, maskedDBLen, emBits, emLen; + unsigned char *H, *salt = NULL, *p; + EVP_MD_CTX ctx; + emBits = BN_num_bits(rsa->n) - 1; + emLen = (emBits + 7) >> 3; + hLen = EVP_MD_size(Hash); + if (sLen < 0) + sLen = 0; + if (emLen < (hLen + sLen + 2)) + { + RSAerr(RSA_F_RSA_PADDING_ADD_PKCS1_PSS, + RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE); + goto err; + } + if (sLen > 0) + { + salt = OPENSSL_malloc(sLen); + if (!salt) + { + RSAerr(RSA_F_RSA_PADDING_ADD_PKCS1_PSS, + ERR_R_MALLOC_FAILURE); + goto err; + } + if (!RAND_bytes(salt, sLen)) + goto err; + } + maskedDBLen = emLen - hLen - 1; + H = EM + maskedDBLen; + EVP_MD_CTX_init(&ctx); + EVP_DigestInit_ex(&ctx, Hash, NULL); + EVP_DigestUpdate(&ctx, zeroes, sizeof zeroes); + EVP_DigestUpdate(&ctx, mHash, hLen); + if (sLen) + EVP_DigestUpdate(&ctx, salt, sLen); + EVP_DigestFinal(&ctx, H, NULL); + EVP_MD_CTX_cleanup(&ctx); + + /* Generate dbMask in place then perform XOR on it */ + PKCS1_MGF1(EM, maskedDBLen, H, hLen, Hash); + + p = EM; + + /* Initial PS XORs with all zeroes which is a NOP so just update + * pointer. Note from a test above this value is guaranteed to + * be non-negative. + */ + p += emLen - sLen - hLen - 2; + *p++ ^= 0x1; + if (sLen > 0) + { + for (i = 0; i < sLen; i++) + *p++ ^= salt[i]; + } + EM[0] &= 0xFF >> (8 - (emBits & 0x7)); + + /* H is already in place so just set final 0xbc */ + + EM[emLen - 1] = 0xbc; + + ret = 1; + + err: + if (salt) + OPENSSL_free(salt); + + return ret; + + } -- 2.25.1