Add PSS support. Minimal at this stage for FIPS140.
authorDr. Stephen Henson <steve@openssl.org>
Fri, 27 May 2005 21:59:52 +0000 (21:59 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Fri, 27 May 2005 21:59:52 +0000 (21:59 +0000)
crypto/rsa/Makefile
crypto/rsa/rsa.h
crypto/rsa/rsa_err.c
crypto/rsa/rsa_oaep.c
crypto/rsa/rsa_pss.c [new file with mode: 0644]

index 5748b0d3d0ea242dfa1f826bc26d1b5805d54923..f69e54771e979c71f6b19b2ba70051e61817b070 100644 (file)
@@ -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)
 
index d18c17ff8b3a5947ce8cc65b2a1be3c34448d78d..cc7107b30e98de765bbb86331b952bdcf906484e 100644 (file)
@@ -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
 }
index 07ef9df0cda8befba2bf37925d58d4a1d460c853..8cbbd05db3fc7576adcc53dca378280ee9e92c9b 100644 (file)
@@ -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}
        };
 
index e3f7c608ec8cf47af734ea56c722ed9d56214013..d43ecaca6309fe17718b2c276d4f151ba0e35981 100644 (file)
@@ -28,9 +28,6 @@
 #include <openssl/rand.h>
 #include <openssl/sha.h>
 
-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 (file)
index 0000000..a470357
--- /dev/null
@@ -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 <stdio.h>
+#include "cryptlib.h"
+#include <openssl/bn.h>
+#include <openssl/rsa.h>
+#include <openssl/evp.h>
+#include <openssl/rand.h>
+#include <openssl/sha.h>
+
+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;
+
+       }