You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@santuario.apache.org by Rahul Kalaskar <ra...@gmail.com> on 2021/12/13 14:42:28 UTC

[xml-security-c] Patch to use newer version of OpenSSL APIs for RSA OAEP

Hi Team,

This is a patch to use newer versions of OpenSSL APIs for RSA OAEP. It
appears the current code exists because OpenSSL 1.0.0 and earlier had no
way to pass custom hash functions. OpenSSL 1.0.2 includes the necessary
APIs.

I have inlined the diff below. Let me know if there is a different way I
should submit it.

-Rahul

32c32
< #if defined(XSEC_HAVE_OPENSSL)
---
> #if defined (XSEC_HAVE_OPENSSL)
34,40d33
< #include <openssl/err.h>
< #include <openssl/rand.h>
< #include <openssl/rsa.h>
< #include <openssl/sha.h>
<
< #include <xercesc/util/Janitor.hpp>
< #include <xsec/enc/OpenSSL/OpenSSLCryptoBase64.hpp>
41a35
> #include <xsec/enc/OpenSSL/OpenSSLCryptoBase64.hpp>
48a43,49
> #include <openssl/err.h>
> #include <openssl/rand.h>
> #include <openssl/rsa.h>
> #include <openssl/sha.h>
>
> #include <xercesc/util/Janitor.hpp>
>
55,60c56,58
< #if OPENSSL_VERSION_NUMBER < 0x10002000
< // This code is modified from OpenSSL to implement SHA-2 hashing with
OAEP.
< // The MGF code is limited to SHA-1 in accordance with the XML Encryption
spec.
< // 0.9.8+ has a public MGF routine to call, this is a copy of it for older
< // versions. Once OpenSSL 1.0.1 (EOL since December 2016) support is
dropped,
< // this code can be removed.
---
>     // This code is modified from OpenSSL to implement SHA-2 hashing with
OAEP.
>     // The MGF code is limited to SHA-1 in accordance with the XML
Encryption spec.
>     // 0.9.8+ has a public MGF routine to call, this is a copy of it for
older versions.
63,96c61,103
< 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[EVP_MAX_MD_SIZE];
<   int mdlen;
<   int rv = -1;
<
<   EVP_MD_CTX_init(&c);
<   mdlen = EVP_MD_size(dgst);
<   if (mdlen < 0) goto err;
<   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);
<     if (!EVP_DigestInit_ex(&c, dgst, NULL) ||
<         !EVP_DigestUpdate(&c, seed, seedlen) || !EVP_DigestUpdate(&c,
cnt, 4))
<       goto err;
<     if (outlen + mdlen <= len) {
<       if (!EVP_DigestFinal_ex(&c, mask + outlen, NULL)) goto err;
<       outlen += mdlen;
<     } else {
<       if (!EVP_DigestFinal_ex(&c, md, NULL)) goto err;
<       memcpy(mask + outlen, md, len - outlen);
<       outlen = len;
<     }
<   }
<   rv = 0;
< err:
<   EVP_MD_CTX_cleanup(&c);
<   return rv;
< }
---
>     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[EVP_MAX_MD_SIZE];
>         int mdlen;
>         int rv = -1;
>
>         EVP_MD_CTX_init(&c);
>         mdlen = EVP_MD_size(dgst);
>         if (mdlen < 0)
>             goto err;
>         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);
>             if (!EVP_DigestInit_ex(&c,dgst, NULL)
>                 || !EVP_DigestUpdate(&c, seed, seedlen)
>                 || !EVP_DigestUpdate(&c, cnt, 4))
>                 goto err;
>             if (outlen + mdlen <= len)
>                 {
>                 if (!EVP_DigestFinal_ex(&c, mask + outlen, NULL))
>                     goto err;
>                 outlen += mdlen;
>                 }
>             else
>                 {
>                 if (!EVP_DigestFinal_ex(&c, md, NULL))
>                     goto err;
>                 memcpy(mask + outlen, md, len - outlen);
>                 outlen = len;
>                 }
>             }
>         rv = 0;
>     err:
>         EVP_MD_CTX_cleanup(&c);
>         return rv;
>     }
99,145c106,109
< static int MGF1(unsigned char* mask, long len, const unsigned char* seed,
<                 long seedlen, const EVP_MD* digest) {
<   return PKCS1_MGF1(mask, len, seed, seedlen, digest);
< }
<
< int RSA_padding_add_PKCS1_OAEP(unsigned char* to, int tlen,
<                                const unsigned char* from, int flen,
<                                const unsigned char* param, int plen,
<                                const EVP_MD* digest, const EVP_MD*
mgf_digest) {
<   int i, digestlen = EVP_MD_size(digest), emlen = tlen - 1;
<   unsigned char *db, *seed;
<   unsigned char *dbmask,
<       seedmask[EVP_MAX_MD_SIZE];  // accomodate largest hash size
<
<   if (flen > emlen - 2 * digestlen - 1) {
<     RSAerr(RSA_F_RSA_PADDING_ADD_PKCS1_OAEP,
RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
<     return 0;
<   }
<
<   if (emlen < 2 * digestlen + 1) {
<     RSAerr(RSA_F_RSA_PADDING_ADD_PKCS1_OAEP, RSA_R_KEY_SIZE_TOO_SMALL);
<     return 0;
<   }
<
<   to[0] = 0;
<   seed = to + 1;
<   db = to + digestlen + 1;
<
<   if (!EVP_Digest((void*)param, plen, db, NULL, digest, NULL)) return 0;
<   memset(db + digestlen, 0, emlen - flen - 2 * digestlen - 1);
<   db[emlen - flen - digestlen - 1] = 0x01;
<   memcpy(db + emlen - flen - digestlen, from, (unsigned int)flen);
<   if (RAND_bytes(seed, digestlen) <= 0) return 0;
<
<   dbmask = (unsigned char*)OPENSSL_malloc(emlen - digestlen);
<   if (dbmask == NULL) {
<     RSAerr(RSA_F_RSA_PADDING_ADD_PKCS1_OAEP, ERR_R_MALLOC_FAILURE);
<     return 0;
<   }
<
<   if (MGF1(dbmask, emlen - digestlen, seed, digestlen, mgf_digest) < 0)
<     return 0;
<   for (i = 0; i < emlen - digestlen; i++) db[i] ^= dbmask[i];
<
<   if (MGF1(seedmask, digestlen, db, emlen - digestlen, mgf_digest) < 0)
<     return 0;
<   for (i = 0; i < digestlen; i++) seed[i] ^= seedmask[i];
---
>     static int MGF1(unsigned char *mask, long len, const unsigned char
*seed, long seedlen, const EVP_MD* digest)
>     {
>         return PKCS1_MGF1(mask, len, seed, seedlen, digest);
>     }
147,149c111,162
<   OPENSSL_free(dbmask);
<   return 1;
< }
---
>     int RSA_padding_add_PKCS1_OAEP(unsigned char *to, int tlen,
>         const unsigned char *from, int flen,
>         const unsigned char *param, int plen,
>         const EVP_MD* digest,
>         const EVP_MD* mgf_digest)
>     {
>         int i, digestlen = EVP_MD_size(digest), emlen = tlen - 1;
>         unsigned char *db, *seed;
>         unsigned char *dbmask, seedmask[EVP_MAX_MD_SIZE];   // accomodate
largest hash size
>
>         if (flen > emlen - 2 * digestlen - 1)
>             {
>             RSAerr(RSA_F_RSA_PADDING_ADD_PKCS1_OAEP,
>                RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
>             return 0;
>             }
>
>         if (emlen < 2 * digestlen + 1)
>             {
>             RSAerr(RSA_F_RSA_PADDING_ADD_PKCS1_OAEP,
RSA_R_KEY_SIZE_TOO_SMALL);
>             return 0;
>             }
>
>         to[0] = 0;
>         seed = to + 1;
>         db = to + digestlen + 1;
>
>         if (!EVP_Digest((void *)param, plen, db, NULL, digest, NULL))
>             return 0;
>         memset(db + digestlen, 0,
>             emlen - flen - 2 * digestlen - 1);
>         db[emlen - flen - digestlen - 1] = 0x01;
>         memcpy(db + emlen - flen - digestlen, from, (unsigned int) flen);
>         if (RAND_bytes(seed, digestlen) <= 0)
>             return 0;
>
>         dbmask = (unsigned char*) OPENSSL_malloc(emlen - digestlen);
>         if (dbmask == NULL)
>             {
>             RSAerr(RSA_F_RSA_PADDING_ADD_PKCS1_OAEP,
ERR_R_MALLOC_FAILURE);
>             return 0;
>             }
>
>         if (MGF1(dbmask, emlen - digestlen, seed, digestlen, mgf_digest)
< 0)
>             return 0;
>         for (i = 0; i < emlen - digestlen; i++)
>             db[i] ^= dbmask[i];
>
>         if (MGF1(seedmask, digestlen, db, emlen - digestlen, mgf_digest)
< 0)
>             return 0;
>         for (i = 0; i < digestlen; i++)
>             seed[i] ^= seedmask[i];
151,230c164,166
< int RSA_padding_check_PKCS1_OAEP(unsigned char* to, int tlen,
<                                  const unsigned char* from, int flen, int
num,
<                                  const unsigned char* param, int plen,
<                                  const EVP_MD* digest,
<                                  const EVP_MD* mgf_digest) {
<   int i, digestlen = EVP_MD_size(digest), dblen, mlen = -1;
<   const unsigned char* maskeddb;
<   int lzero;
<   unsigned char *db = NULL, seed[EVP_MAX_MD_SIZE], phash[EVP_MAX_MD_SIZE];
<   unsigned char* padded_from;
<   int bad = 0;
<
<   if (--num < 2 * digestlen + 1)
<     /* 'num' is the length of the modulus, i.e. does not depend on the
<      * particular ciphertext. */
<     goto decoding_err;
<
<   lzero = num - flen;
<   if (lzero < 0) {
<     /* signalling this error immediately after detection might allow
<      * for side-channel attacks (e.g. timing if 'plen' is huge
<      * -- cf. James H. Manger, "A Chosen Ciphertext Attack on RSA Optimal
<      * Asymmetric Encryption Padding (OAEP) [...]", CRYPTO 2001),
<      * so we use a 'bad' flag */
<     bad = 1;
<     lzero = 0;
<     flen = num; /* don't overflow the memcpy to padded_from */
<   }
<
<   dblen = num - digestlen;
<   db = (unsigned char*)OPENSSL_malloc(dblen + num);
<   if (db == NULL) {
<     RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_OAEP, ERR_R_MALLOC_FAILURE);
<     return -1;
<   }
<
<   /* Always do this zero-padding copy (even when lzero == 0)
<    * to avoid leaking timing info about the value of lzero. */
<   padded_from = db + dblen;
<   memset(padded_from, 0, lzero);
<   memcpy(padded_from + lzero, from, flen);
<
<   maskeddb = padded_from + digestlen;
<
<   if (MGF1(seed, digestlen, maskeddb, dblen, mgf_digest)) return -1;
<   for (i = 0; i < digestlen; i++) seed[i] ^= padded_from[i];
<
<   if (MGF1(db, dblen, seed, digestlen, mgf_digest)) return -1;
<   for (i = 0; i < dblen; i++) db[i] ^= maskeddb[i];
<
<   if (!EVP_Digest((void*)param, plen, phash, NULL, digest, NULL)) return
-1;
<
<   if (memcmp(db, phash, digestlen) != 0 || bad)
<     goto decoding_err;
<   else {
<     for (i = digestlen; i < dblen; i++)
<       if (db[i] != 0x00) break;
<     if (i == dblen || db[i] != 0x01)
<       goto decoding_err;
<     else {
<       /* everything looks OK */
<
<       mlen = dblen - ++i;
<       if (tlen < mlen) {
<         RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_OAEP, RSA_R_DATA_TOO_LARGE);
<         mlen = -1;
<       } else
<         memcpy(to, db + i, mlen);
<     }
<   }
<   OPENSSL_free(db);
<   return mlen;
<
< decoding_err:
<   /* to avoid chosen ciphertext attacks, the error message should not
reveal
<    * which kind of decoding error happened */
<   RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_OAEP, RSA_R_OAEP_DECODING_ERROR);
<   if (db != NULL) OPENSSL_free(db);
<   return -1;
< }
---
>         OPENSSL_free(dbmask);
>         return 1;
>     }
232c168,260
< #endif
---
>     int RSA_padding_check_PKCS1_OAEP(unsigned char *to, int tlen,
>         const unsigned char *from, int flen, int num,
>         const unsigned char *param, int plen,
>         const EVP_MD* digest,
>         const EVP_MD* mgf_digest)
>     {
>         int i, digestlen = EVP_MD_size(digest), dblen, mlen = -1;
>         const unsigned char *maskeddb;
>         int lzero;
>         unsigned char *db = NULL, seed[EVP_MAX_MD_SIZE],
phash[EVP_MAX_MD_SIZE];
>         unsigned char *padded_from;
>         int bad = 0;
>
>         if (--num < 2 * digestlen + 1)
>             /* 'num' is the length of the modulus, i.e. does not depend
on the
>              * particular ciphertext. */
>             goto decoding_err;
>
>         lzero = num - flen;
>         if (lzero < 0)
>             {
>             /* signalling this error immediately after detection might
allow
>              * for side-channel attacks (e.g. timing if 'plen' is huge
>              * -- cf. James H. Manger, "A Chosen Ciphertext Attack on RSA
Optimal
>              * Asymmetric Encryption Padding (OAEP) [...]", CRYPTO 2001),
>              * so we use a 'bad' flag */
>             bad = 1;
>             lzero = 0;
>             flen = num; /* don't overflow the memcpy to padded_from */
>             }
>
>         dblen = num - digestlen;
>         db = (unsigned char*) OPENSSL_malloc(dblen + num);
>         if (db == NULL)
>             {
>             RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_OAEP,
ERR_R_MALLOC_FAILURE);
>             return -1;
>             }
>
>         /* Always do this zero-padding copy (even when lzero == 0)
>          * to avoid leaking timing info about the value of lzero. */
>         padded_from = db + dblen;
>         memset(padded_from, 0, lzero);
>         memcpy(padded_from + lzero, from, flen);
>
>         maskeddb = padded_from + digestlen;
>
>         if (MGF1(seed, digestlen, maskeddb, dblen, mgf_digest))
>             return -1;
>         for (i = 0; i < digestlen; i++)
>             seed[i] ^= padded_from[i];
>
>         if (MGF1(db, dblen, seed, digestlen, mgf_digest))
>             return -1;
>         for (i = 0; i < dblen; i++)
>             db[i] ^= maskeddb[i];
>
>         if (!EVP_Digest((void *)param, plen, phash, NULL, digest, NULL))
>             return -1;
>
>         if (memcmp(db, phash, digestlen) != 0 || bad)
>             goto decoding_err;
>         else
>             {
>             for (i = digestlen; i < dblen; i++)
>                 if (db[i] != 0x00)
>                     break;
>             if (i == dblen || db[i] != 0x01)
>                 goto decoding_err;
>             else
>                 {
>                 /* everything looks OK */
>
>                 mlen = dblen - ++i;
>                 if (tlen < mlen)
>                     {
>                     RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_OAEP,
RSA_R_DATA_TOO_LARGE);
>                     mlen = -1;
>                     }
>                 else
>                     memcpy(to, db + i, mlen);
>                 }
>             }
>         OPENSSL_free(db);
>         return mlen;
>
>     decoding_err:
>         /* to avoid chosen ciphertext attacks, the error message should
not reveal
>          * which kind of decoding error happened */
>         RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_OAEP,
RSA_R_OAEP_DECODING_ERROR);
>         if (db != NULL) OPENSSL_free(db);
>         return -1;
>     }
234c262
< };  // namespace
---
> };
237d264
<   const EVP_MD* evp_md = NULL;
239,254c266
<   switch (type) {
<     case XSECCryptoHash::HASH_SHA1:
<       evp_md = EVP_get_digestbyname("SHA1");
<       break;
<     case XSECCryptoHash::HASH_SHA224:
<       evp_md = EVP_get_digestbyname("SHA224");
<       break;
<     case XSECCryptoHash::HASH_SHA256:
<       evp_md = EVP_get_digestbyname("SHA256");
<       break;
<     case XSECCryptoHash::HASH_SHA384:
<       evp_md = EVP_get_digestbyname("SHA384");
<       break;
<     case XSECCryptoHash::HASH_SHA512:
<       evp_md = EVP_get_digestbyname("SHA512");
<       break;
---
>     const EVP_MD* evp_md = NULL;
256,257c268,283
<     default:;
<   }
---
>     switch (type) {
>         case XSECCryptoHash::HASH_SHA1:
>             evp_md = EVP_get_digestbyname("SHA1");
>             break;
>         case XSECCryptoHash::HASH_SHA224:
>             evp_md = EVP_get_digestbyname("SHA224");
>             break;
>         case XSECCryptoHash::HASH_SHA256:
>             evp_md = EVP_get_digestbyname("SHA256");
>             break;
>         case XSECCryptoHash::HASH_SHA384:
>             evp_md = EVP_get_digestbyname("SHA384");
>             break;
>         case XSECCryptoHash::HASH_SHA512:
>             evp_md = EVP_get_digestbyname("SHA512");
>             break;
259c285,289
<   return evp_md;
---
>         default:
>             ;
>     }
>
>     return evp_md;
262,263c292,298
< OpenSSLCryptoKeyRSA::OpenSSLCryptoKeyRSA()
<     : mp_rsaKey(NULL), mp_accumE(NULL), mp_accumN(NULL){};
---
>
> OpenSSLCryptoKeyRSA::OpenSSLCryptoKeyRSA() :
>     mp_rsaKey(NULL),
>     mp_accumE(NULL),
>     mp_accumN(NULL)
> {
> };
266c301
<   // If we have a RSA, delete it (OpenSSL will clear the memory)
---
>     // If we have a RSA, delete it (OpenSSL will clear the memory)
268c303,304
<   if (mp_rsaKey) RSA_free(mp_rsaKey);
---
>     if (mp_rsaKey)
>         RSA_free(mp_rsaKey);
270c306,307
<   if (mp_accumE) BN_free(mp_accumE);
---
>     if (mp_accumE)
>         BN_free(mp_accumE);
272c309,310
<   if (mp_accumN) BN_free(mp_accumN);
---
>     if (mp_accumN)
>         BN_free(mp_accumN);
276c314
<   return DSIGConstants::s_unicodeStrPROVOpenSSL;
---
>     return DSIGConstants::s_unicodeStrPROVOpenSSL;
278a317
>
282,283d320
<   // Find out what we have
<   if (mp_rsaKey == NULL) return KEY_NONE;
285,286c322,327
<   const BIGNUM *n, *d;
<   RSA_get0_key(mp_rsaKey, &n, NULL, &d);
---
>     // Find out what we have
>     if (mp_rsaKey == NULL)
>         return KEY_NONE;
>
>     const BIGNUM *n, *d;
>     RSA_get0_key(mp_rsaKey, &n, NULL, &d);
288c329,330
<   if (n != NULL && d != NULL) return KEY_RSA_PAIR;
---
>     if (n != NULL && d != NULL)
>         return KEY_RSA_PAIR;
290c332,333
<   if (d != NULL) return KEY_RSA_PRIVATE;
---
>     if (d != NULL)
>         return KEY_RSA_PRIVATE;
292c335,336
<   if (n != NULL) return KEY_RSA_PUBLIC;
---
>     if (n != NULL)
>         return KEY_RSA_PUBLIC;
294c338
<   return KEY_NONE;
---
>     return KEY_NONE;
297,299c341,342
< void OpenSSLCryptoKeyRSA::loadPublicModulusBase64BigNums(const char* b64,
<                                                          unsigned int
len) {
<   setNBase(OpenSSLCryptoBase64::b642BN((char*)b64, len));
---
> void OpenSSLCryptoKeyRSA::loadPublicModulusBase64BigNums(const char* b64,
unsigned int len) {
>     setNBase(OpenSSLCryptoBase64::b642BN((char *) b64, len));
302,303c345,348
< void OpenSSLCryptoKeyRSA::setNBase(BIGNUM* nBase) {
<   if (mp_rsaKey == NULL) mp_rsaKey = RSA_new();
---
> void OpenSSLCryptoKeyRSA::setNBase(BIGNUM *nBase) {
>
>     if (mp_rsaKey == NULL)
>         mp_rsaKey = RSA_new();
307c352
<   mp_rsaKey->n = nBase;
---
>     mp_rsaKey->n = nBase;
311c356,357
<   if (mp_accumN) BN_free(mp_accumN);
---
>     if (mp_accumN)
>         BN_free(mp_accumN);
313,314c359,360
<   mp_accumN = nBase;
<   commitEN();
---
>     mp_accumN = nBase;
>     commitEN();
318,320c364,366
< void OpenSSLCryptoKeyRSA::loadPublicExponentBase64BigNums(const char* b64,
<                                                           unsigned int
len) {
<   setEBase(OpenSSLCryptoBase64::b642BN((char*)b64, len));
---
>
> void OpenSSLCryptoKeyRSA::loadPublicExponentBase64BigNums(const char*
b64, unsigned int len) {
>     setEBase(OpenSSLCryptoBase64::b642BN((char *) b64, len));
323,324c369,373
< void OpenSSLCryptoKeyRSA::setEBase(BIGNUM* eBase) {
<   if (mp_rsaKey == NULL) mp_rsaKey = RSA_new();
---
>
> void OpenSSLCryptoKeyRSA::setEBase(BIGNUM *eBase) {
>
>     if (mp_rsaKey == NULL)
>         mp_rsaKey = RSA_new();
327c376
<   mp_rsaKey->e = eBase;
---
>     mp_rsaKey->e = eBase;
330c379,380
<   if (mp_accumE) BN_free(mp_accumE);
---
>     if (mp_accumE)
>         BN_free(mp_accumE);
332,333c382,383
<   mp_accumE = eBase;
<   commitEN();
---
>     mp_accumE = eBase;
>     commitEN();
339d388
<   if (NULL == mp_accumN || NULL == mp_accumE) return;
341c390,391
<   RSA_set0_key(mp_rsaKey, mp_accumN, mp_accumE, NULL);
---
>     if (NULL == mp_accumN || NULL == mp_accumE)
>         return;
343,344c393,397
<   mp_accumN = NULL;
<   mp_accumE = NULL;
---
>
>     RSA_set0_key(mp_rsaKey, mp_accumN, mp_accumE, NULL);
>
>     mp_accumN = NULL;
>     mp_accumE = NULL;
350,374c403,431
< OpenSSLCryptoKeyRSA::OpenSSLCryptoKeyRSA(EVP_PKEY* k)
<     : mp_rsaKey(NULL), mp_accumE(NULL), mp_accumN(NULL) {
<   // Create a new key to be loaded as we go
<
<   mp_rsaKey = RSA_new();
<
<   if (k == NULL || EVP_PKEY_id(k) != EVP_PKEY_RSA)
<     return;  // Nothing to do with us
<
<   RSA* rsa = EVP_PKEY_get0_RSA(k);
<
<   const BIGNUM *n = NULL, *e = NULL, *d = NULL;
<   RSA_get0_key(rsa, &n, &e, &d);
<   if (n && e)  // Do not dup unless setter will work
<     RSA_set0_key(mp_rsaKey, DUP_NON_NULL(n), DUP_NON_NULL(e),
DUP_NON_NULL(d));
<
<   const BIGNUM *p = NULL, *q = NULL;
<   RSA_get0_factors(rsa, &p, &q);
<   if (p && q) RSA_set0_factors(mp_rsaKey, DUP_NON_NULL(p),
DUP_NON_NULL(q));
<
<   const BIGNUM *dmp1 = NULL, *dmq1 = NULL, *iqmp = NULL;
<   RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp);
<   if (dmp1 && dmq1 && iqmp)
<     RSA_set0_crt_params(mp_rsaKey, DUP_NON_NULL(dmp1), DUP_NON_NULL(dmq1),
<                         DUP_NON_NULL(iqmp));
---
> OpenSSLCryptoKeyRSA::OpenSSLCryptoKeyRSA(EVP_PKEY *k) :
>     mp_rsaKey(NULL),
>     mp_accumE(NULL),
>     mp_accumN(NULL)
> {
>
>     // Create a new key to be loaded as we go
>
>     mp_rsaKey = RSA_new();
>
>     if (k == NULL || EVP_PKEY_id(k) != EVP_PKEY_RSA)
>         return; // Nothing to do with us
>
>     RSA *rsa = EVP_PKEY_get0_RSA(k);
>
>     const BIGNUM *n=NULL, *e=NULL, *d=NULL;
>     RSA_get0_key(rsa, &n, &e, &d);
>     if (n && e) // Do not dup unless setter will work
>         RSA_set0_key(mp_rsaKey, DUP_NON_NULL(n), DUP_NON_NULL(e),
DUP_NON_NULL(d));
>
>     const BIGNUM *p=NULL, *q=NULL;
>     RSA_get0_factors(rsa, &p, &q);
>     if (p && q)
>         RSA_set0_factors(mp_rsaKey, DUP_NON_NULL(p), DUP_NON_NULL(q));
>
>     const BIGNUM *dmp1=NULL, *dmq1=NULL, *iqmp=NULL;
>     RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp);
>     if (dmp1 && dmq1 &&  iqmp)
>         RSA_set0_crt_params(mp_rsaKey, DUP_NON_NULL(dmp1),
DUP_NON_NULL(dmq1), DUP_NON_NULL(iqmp));
382,490c439,539
<     const unsigned char* hashBuf, unsigned int hashLen,
<     const char* base64Signature, unsigned int sigLen,
<     XSECCryptoHash::HashType type) const {
<   // Use the currently loaded key to validate the Base64 encoded signature
<
<   if (mp_rsaKey == NULL) {
<     throw XSECCryptoException(
<         XSECCryptoException::RSAError,
<         "OpenSSL:RSA - Attempt to validate signature with empty key");
<   }
<
<   XSECCryptoKey::KeyType keyType = getKeyType();
<   if (keyType != KEY_RSA_PAIR && keyType != KEY_RSA_PUBLIC) {
<     throw XSECCryptoException(
<         XSECCryptoException::RSAError,
<         "OpenSSL:RSA - Attempt to validate signature without public key");
<   }
<
<   char* cleanedBase64Signature;
<   unsigned int cleanedBase64SignatureLen = 0;
<
<   cleanedBase64Signature = XSECCryptoBase64::cleanBuffer(
<       base64Signature, sigLen, cleanedBase64SignatureLen);
<   ArrayJanitor<char> j_cleanedBase64Signature(cleanedBase64Signature);
<
<   int sigValLen;
<   unsigned char* sigVal = new unsigned char[sigLen + 1];
<   ArrayJanitor<unsigned char> j_sigVal(sigVal);
<
<   EvpEncodeCtxRAII dctx;
<
<   if (!dctx.of()) {
<     throw XSECCryptoException(
<         XSECCryptoException::RSAError,
<         "OpenSSL:RSA - allocation fail during Context Creation");
<   }
<
<   EVP_DecodeInit(dctx.of());
<   int rc = EVP_DecodeUpdate(dctx.of(), sigVal, &sigValLen,
<                             (unsigned char*)cleanedBase64Signature,
<                             cleanedBase64SignatureLen);
<
<   if (rc < 0) {
<     throw XSECCryptoException(XSECCryptoException::RSAError,
<                               "OpenSSL:RSA - Error during Base64 Decode");
<   }
<   int t = 0;
<
<   EVP_DecodeFinal(dctx.of(), &sigVal[sigValLen], &t);
<
<   sigValLen += t;
<
<   // OpenSSL allows the signature size to be less than the key size.
<   // Java does not and the spec requires that this fail, so we have to
<   // perform this check.
<
<   int keySize = RSA_size(mp_rsaKey);
<   if (keySize != sigValLen) {
<     throw XSECCryptoException(
<         XSECCryptoException::RSAError,
<         "OpenSSL:RSA - Signature size does not match key size");
<   }
<
<   // Now decrypt
<
<   unsigned char* decryptBuf;
<
<   // Decrypt will always be longer than (RSA_len(key) - 11)
<   decryptBuf = new unsigned char[RSA_size(mp_rsaKey)];
<   ArrayJanitor<unsigned char> j_decryptBuf(decryptBuf);
<
<   // Note at this time only supports PKCS1 padding
<   // As that is what is defined in the standard.
<   // If this ever changes we will need to pass some paramaters
<   // into this function to allow it to determine what the
<   // padding should be and what the message digest OID should
<   // be.
<
<   int decryptSize = RSA_public_decrypt(sigValLen, sigVal, decryptBuf,
mp_rsaKey,
<                                        RSA_PKCS1_PADDING);
<
<   if (decryptSize < 0) {
<     // Really - this is a failed signature check, not an exception!
<     return false;
<   }
<
<   /* Check the OID */
<   int oidLen = 0;
<   unsigned char* oid = getRSASigOID(type, oidLen);
<
<   if (oid == NULL) {
<     throw XSECCryptoException(
<         XSECCryptoException::RSAError,
<         "OpenSSL:RSA::verify() - Unsupported HASH algorithm for RSA");
<   }
<
<   if (decryptSize != (int)(oidLen + hashLen) || hashLen != oid[oidLen -
1]) {
<     return false;
<   }
<
<   for (t = 0; t < oidLen; ++t) {
<     if (oid[t] != decryptBuf[t]) {
<       return false;
<     }
<   }
<
<   for (; t < decryptSize; ++t) {
<     if (hashBuf[t - oidLen] != decryptBuf[t]) {
<       return false;
---
>         const unsigned char* hashBuf,
>         unsigned int hashLen,
>         const char * base64Signature,
>         unsigned int sigLen,
>         XSECCryptoHash::HashType type) const {
>
>     // Use the currently loaded key to validate the Base64 encoded
signature
>
>     if (mp_rsaKey == NULL) {
>         throw XSECCryptoException(XSECCryptoException::RSAError,
>             "OpenSSL:RSA - Attempt to validate signature with empty key");
>     }
>
>     XSECCryptoKey::KeyType keyType = getKeyType();
>     if (keyType != KEY_RSA_PAIR && keyType != KEY_RSA_PUBLIC) {
>         throw XSECCryptoException(XSECCryptoException::RSAError,
>             "OpenSSL:RSA - Attempt to validate signature without public
key");
>     }
>
>     char* cleanedBase64Signature;
>     unsigned int cleanedBase64SignatureLen = 0;
>
>     cleanedBase64Signature =
>         XSECCryptoBase64::cleanBuffer(base64Signature, sigLen,
cleanedBase64SignatureLen);
>     ArrayJanitor<char> j_cleanedBase64Signature(cleanedBase64Signature);
>
>     int sigValLen;
>     unsigned char* sigVal = new unsigned char[sigLen + 1];
>     ArrayJanitor<unsigned char> j_sigVal(sigVal);
>
>     EvpEncodeCtxRAII dctx;
>
>     if (!dctx.of()) {
>         throw XSECCryptoException(XSECCryptoException::RSAError,
>             "OpenSSL:RSA - allocation fail during Context Creation");
>     }
>
>     EVP_DecodeInit(dctx.of());
>     int rc = EVP_DecodeUpdate(dctx.of(),
>                           sigVal,
>                           &sigValLen,
>                           (unsigned char *) cleanedBase64Signature,
>                           cleanedBase64SignatureLen);
>
>     if (rc < 0) {
>         throw XSECCryptoException(XSECCryptoException::RSAError,
>             "OpenSSL:RSA - Error during Base64 Decode");
>     }
>     int t = 0;
>
>     EVP_DecodeFinal(dctx.of(), &sigVal[sigValLen], &t);
>
>     sigValLen += t;
>
>     // OpenSSL allows the signature size to be less than the key size.
>     // Java does not and the spec requires that this fail, so we have to
>     // perform this check.
>
>     int keySize = RSA_size(mp_rsaKey);
>     if (keySize != sigValLen) {
>             throw XSECCryptoException(XSECCryptoException::RSAError,
>                 "OpenSSL:RSA - Signature size does not match key size");
>     }
>
>     // Now decrypt
>
>     unsigned char* decryptBuf;
>
>     // Decrypt will always be longer than (RSA_len(key) - 11)
>     decryptBuf = new unsigned char[RSA_size(mp_rsaKey)];
>     ArrayJanitor<unsigned char> j_decryptBuf(decryptBuf);
>
>     // Note at this time only supports PKCS1 padding
>     // As that is what is defined in the standard.
>     // If this ever changes we will need to pass some paramaters
>     // into this function to allow it to determine what the
>     // padding should be and what the message digest OID should
>     // be.
>
>     int decryptSize = RSA_public_decrypt(sigValLen,
>                                              sigVal,
>                                              decryptBuf,
>                                              mp_rsaKey,
>                                              RSA_PKCS1_PADDING);
>
>     if (decryptSize < 0) {
>         // Really - this is a failed signature check, not an exception!
>         return false;
>     }
>
>     /* Check the OID */
>     int oidLen = 0;
>     unsigned char * oid = getRSASigOID(type, oidLen);
>
>     if (oid == NULL) {
>         throw XSECCryptoException(XSECCryptoException::RSAError,
>             "OpenSSL:RSA::verify() - Unsupported HASH algorithm for RSA");
>     }
>
>     if (decryptSize != (int) (oidLen + hashLen) || hashLen !=
oid[oidLen-1]) {
>         return false;
492d540
<   }
494,495c542,555
<   // All OK
<   return true;
---
>     for (t = 0; t < oidLen; ++t) {
>         if (oid[t] != decryptBuf[t]) {
>             return false;
>         }
>     }
>
>     for (;t < decryptSize; ++t) {
>         if (hashBuf[t-oidLen] != decryptBuf[t]) {
>             return false;
>         }
>     }
>
>     // All OK
>     return true;
501a562
>
503,548c564,568
<     unsigned char* hashBuf, unsigned int hashLen, char*
base64SignatureBuf,
<     unsigned int base64SignatureBufLen, XSECCryptoHash::HashType type)
const {
<   // Sign a pre-calculated hash using this key
<
<   if (mp_rsaKey == NULL) {
<     throw XSECCryptoException(
<         XSECCryptoException::RSAError,
<         "OpenSSL:RSA - Attempt to sign data with empty key");
<   }
<
<   KeyType keyType = getKeyType();
<   if (keyType != KEY_RSA_PAIR && keyType != KEY_RSA_PRIVATE) {
<     throw XSECCryptoException(
<         XSECCryptoException::RSAError,
<         "OpenSSL:RSA - Attempt to sign data without private key");
<   }
<
<   // Build the buffer to be encrypted by prepending the SHA1 OID to the
hash
<
<   unsigned char* encryptBuf;
<   unsigned char* preEncryptBuf;
<   unsigned char* oid;
<   int oidLen;
<   int encryptLen;
<   int preEncryptLen;
<
<   oid = getRSASigOID(type, oidLen);
<
<   if (oid == NULL) {
<     throw XSECCryptoException(
<         XSECCryptoException::RSAError,
<         "OpenSSL:RSA::sign() - Unsupported HASH algorithm for RSA");
<   }
<
<   if (hashLen != oid[oidLen - 1]) {
<     throw XSECCryptoException(
<         XSECCryptoException::RSAError,
<         "OpenSSL:RSA::sign() - hashLen incorrect for hash type");
<   }
<
<   preEncryptLen = hashLen + oidLen;
<   preEncryptBuf = new unsigned char[preEncryptLen];
<   encryptBuf = new unsigned char[RSA_size(mp_rsaKey)];
<
<   memcpy(preEncryptBuf, oid, oidLen);
<   memcpy(&preEncryptBuf[oidLen], hashBuf, hashLen);
---
>         unsigned char* hashBuf,
>         unsigned int hashLen,
>         char * base64SignatureBuf,
>         unsigned int base64SignatureBufLen,
>         XSECCryptoHash::HashType type) const {
550c570
<   // Now encrypt
---
>     // Sign a pre-calculated hash using this key
552,553c572,575
<   encryptLen = RSA_private_encrypt(preEncryptLen, preEncryptBuf,
encryptBuf,
<                                    mp_rsaKey, RSA_PKCS1_PADDING);
---
>     if (mp_rsaKey == NULL) {
>         throw XSECCryptoException(XSECCryptoException::RSAError,
>             "OpenSSL:RSA - Attempt to sign data with empty key");
>     }
555c577,581
<   delete[] preEncryptBuf;
---
>     KeyType keyType = getKeyType();
>     if (keyType != KEY_RSA_PAIR && keyType != KEY_RSA_PRIVATE) {
>         throw XSECCryptoException(XSECCryptoException::RSAError,
>             "OpenSSL:RSA - Attempt to sign data without private key");
>     }
557,561c583
<   if (encryptLen < 0) {
<     delete[] encryptBuf;
<     throw XSECCryptoException(XSECCryptoException::RSAError,
<                               "OpenSSL:RSA::sign() - Error encrypting
hash");
<   }
---
>     // Build the buffer to be encrypted by prepending the SHA1 OID to the
hash
563c585,590
<   // Now convert to Base 64
---
>     unsigned char* encryptBuf;
>     unsigned char* preEncryptBuf;
>     unsigned char* oid;
>     int oidLen;
>     int encryptLen;
>     int preEncryptLen;
565,566c592,625
<   BIO* b64 = BIO_new(BIO_f_base64());
<   BIO* bmem = BIO_new(BIO_s_mem());
---
>     oid = getRSASigOID(type, oidLen);
>
>     if (oid == NULL) {
>         throw XSECCryptoException(XSECCryptoException::RSAError,
>             "OpenSSL:RSA::sign() - Unsupported HASH algorithm for RSA");
>     }
>
>     if (hashLen != oid[oidLen-1]) {
>         throw XSECCryptoException(XSECCryptoException::RSAError,
>             "OpenSSL:RSA::sign() - hashLen incorrect for hash type");
>     }
>
>     preEncryptLen = hashLen + oidLen;
>     preEncryptBuf = new unsigned char[preEncryptLen];
>     encryptBuf = new unsigned char[RSA_size(mp_rsaKey)];
>
>     memcpy(preEncryptBuf, oid, oidLen);
>     memcpy(&preEncryptBuf[oidLen], hashBuf, hashLen);
>
>     // Now encrypt
>
>     encryptLen = RSA_private_encrypt(preEncryptLen,
>                                      preEncryptBuf,
>                                      encryptBuf,
>                                      mp_rsaKey,
>                                      RSA_PKCS1_PADDING);
>
>     delete[] preEncryptBuf;
>
>     if (encryptLen < 0) {
>         delete[] encryptBuf;
>         throw XSECCryptoException(XSECCryptoException::RSAError,
>             "OpenSSL:RSA::sign() - Error encrypting hash");
>     }
568,569c627
<   BIO_set_mem_eof_return(bmem, 0);
<   b64 = BIO_push(b64, bmem);
---
>     // Now convert to Base 64
571c629,630
<   // Translate signature to Base64
---
>     BIO * b64 = BIO_new(BIO_f_base64());
>     BIO * bmem = BIO_new(BIO_s_mem());
573,574c632,633
<   BIO_write(b64, encryptBuf, encryptLen);
<   BIO_flush(b64);
---
>     BIO_set_mem_eof_return(bmem, 0);
>     b64 = BIO_push(b64, bmem);
576,577c635
<   unsigned int sigValLen =
<       BIO_read(bmem, base64SignatureBuf, base64SignatureBufLen);
---
>     // Translate signature to Base64
579c637,638
<   BIO_free_all(b64);
---
>     BIO_write(b64, encryptBuf, encryptLen);
>     BIO_flush(b64);
581c640
<   delete[] encryptBuf;
---
>     unsigned int sigValLen = BIO_read(bmem, base64SignatureBuf,
base64SignatureBufLen);
583,586c642
<   if (sigValLen <= 0) {
<     throw XSECCryptoException(XSECCryptoException::DSAError,
<                               "OpenSSL:RSA - Error base64 encoding
signature");
<   }
---
>     BIO_free_all(b64);
588c644,651
<   return sigValLen;
---
>     delete[] encryptBuf;
>
>     if (sigValLen <= 0) {
>         throw XSECCryptoException(XSECCryptoException::DSAError,
>             "OpenSSL:RSA - Error base64 encoding signature");
>     }
>
>     return sigValLen;
596,604c659,673
<     const unsigned char* inBuf, unsigned char* plainBuf, unsigned int
inLength,
<     unsigned int maxOutLength, PaddingType padding, const XMLCh* hashURI,
<     const XMLCh* mgfURI, unsigned char* params, unsigned int paramslen)
const {
<   // Perform a decrypt
<   if (mp_rsaKey == NULL) {
<     throw XSECCryptoException(
<         XSECCryptoException::RSAError,
<         "OpenSSL:RSA - Attempt to decrypt data with empty key");
<   }
---
>         const unsigned char* inBuf,
>         unsigned char* plainBuf,
>         unsigned int inLength,
>         unsigned int maxOutLength,
>         PaddingType padding,
>         const XMLCh* hashURI,
>         const XMLCh* mgfURI,
>         unsigned char* params,
>         unsigned int paramslen) const {
>
>     // Perform a decrypt
>     if (mp_rsaKey == NULL) {
>         throw XSECCryptoException(XSECCryptoException::RSAError,
>             "OpenSSL:RSA - Attempt to decrypt data with empty key");
>     }
619c688
<   int decryptSize;
---
>     int decryptSize;
621,622c690
<   switch (padding) {
<     case XSECCryptoKeyRSA::PAD_PKCS_1_5:
---
>     switch (padding) {
624c692,694
<       decryptSize = RSA_private_decrypt(inLength,
---
>     case XSECCryptoKeyRSA::PAD_PKCS_1_5 :
>
>         decryptSize = RSA_private_decrypt(inLength,
626c696
<                                         inBuf,
---
>                             inBuf,
628c698
<                                         (unsigned char*)inBuf,
---
>                             (unsigned char *) inBuf,
630c700,707
<                                         plainBuf, mp_rsaKey,
RSA_PKCS1_PADDING);
---
>                             plainBuf,
>                             mp_rsaKey,
>                             RSA_PKCS1_PADDING);
>
>         if (decryptSize < 0) {
>             throw XSECCryptoException(XSECCryptoException::RSAError,
>                 "OpenSSL:RSA privateKeyDecrypt - Error Decrypting PKCS1_5
padded RSA encrypt");
>         }
632,663c709,729
<       if (decryptSize < 0) {
<         throw XSECCryptoException(XSECCryptoException::RSAError,
<                                   "OpenSSL:RSA privateKeyDecrypt - Error "
<                                   "Decrypting PKCS1_5 padded RSA
encrypt");
<       }
<
<       break;
<
<     case XSECCryptoKeyRSA::PAD_OAEP: {
<       const EVP_MD* evp_md =
<
getDigestFromHashType(XSECAlgorithmSupport::getHashType(hashURI));
<       if (evp_md == NULL) {
<         throw XSECCryptoException(
<             XSECCryptoException::UnsupportedAlgorithm,
<             "OpenSSL:RSA - OAEP digest algorithm not supported");
<       }
<
<       const EVP_MD* mgf_md =
<
getDigestFromHashType(XSECAlgorithmSupport::getMGF1HashType(mgfURI));
<       if (mgf_md == NULL) {
<         throw XSECCryptoException(
<             XSECCryptoException::UnsupportedAlgorithm,
<             "OpenSSL:RSA - OAEP MGF algorithm not supported");
<       }
<
< #if OPENSSL_VERSION_NUMBER < 0x10002000
<       // Once OpenSSL 1.0.1 (EOL since December 2016) support is dropped,
this
<       // code may be removed.
<       unsigned char* tBuf;
<       int num = RSA_size(mp_rsaKey);
<       XSECnew(tBuf, unsigned char[num]);
<       ArrayJanitor<unsigned char> j_tBuf(tBuf);
---
>         break;
>
>     case XSECCryptoKeyRSA::PAD_OAEP :
>         {
>             const EVP_MD* evp_md =
getDigestFromHashType(XSECAlgorithmSupport::getHashType(hashURI));
>             if (evp_md == NULL) {
>                 throw
XSECCryptoException(XSECCryptoException::UnsupportedAlgorithm,
>                     "OpenSSL:RSA - OAEP digest algorithm not supported");
>             }
>
>
>             const EVP_MD* mgf_md =
getDigestFromHashType(XSECAlgorithmSupport::getMGF1HashType(mgfURI));
>             if (mgf_md == NULL) {
>                 throw
XSECCryptoException(XSECCryptoException::UnsupportedAlgorithm,
>                     "OpenSSL:RSA - OAEP MGF algorithm not supported");
>             }
>
>             unsigned char * tBuf;
>             int num = RSA_size(mp_rsaKey);
>             XSECnew(tBuf, unsigned char[num]);
>             ArrayJanitor<unsigned char> j_tBuf(tBuf);
665c731
<       decryptSize = RSA_private_decrypt(inLength,
---
>             decryptSize = RSA_private_decrypt(inLength,
667,690c733
<                                         inBuf,
< #else
<                                         (unsigned char*)inBuf,
< #endif
<                                         tBuf, mp_rsaKey, RSA_NO_PADDING);
<       if (decryptSize < 0) {
<         throw XSECCryptoException(XSECCryptoException::RSAError,
<                                   "OpenSSL:RSA privateKeyDecrypt - Error
doing "
<                                   "raw decrypt of RSA encrypted data");
<       }
<
<       // Clear out the "0"s at the front
<       int i;
<       for (i = 0; i < num && tBuf[i] == 0; ++i) --decryptSize;
<
<       decryptSize = RSA_padding_check_PKCS1_OAEP(
<           plainBuf, maxOutLength, &tBuf[i], decryptSize, num, params,
paramslen,
<           evp_md, mgf_md);
<
<       if (decryptSize < 0) {
<         throw XSECCryptoException(
<             XSECCryptoException::RSAError,
<             "OpenSSL:RSA privateKeyDecrypt - Error removing OAEPadding");
<       }
---
>                                 inBuf,
692,717c735
<       EVP_PKEY* pkey = EVP_PKEY_new();
<       if (pkey == NULL || EVP_PKEY_set1_RSA(pkey, mp_rsaKey) <= 0) {
<         EVP_PKEY_free(pkey);
<         throw XSECCryptoException(XSECCryptoException::RSAError,
<                                   "OpenSSL:RSA privateKeyDecrypt - Error "
<                                   "wrapping RSA key");
<       }
<
<       size_t len = maxOutLength;
<       EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new(pkey, NULL);
<       bool ok =
<           ctx != NULL &&
<           EVP_PKEY_decrypt_init(ctx) == 1 &&
<           EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) == 1
&&
<           EVP_PKEY_CTX_set_rsa_oaep_md(ctx, evp_md) == 1 &&
<           EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, mgf_md) == 1 &&
<           EVP_PKEY_decrypt(ctx, plainBuf, &len, inBuf, inLength) == 1;
<       EVP_PKEY_CTX_free(ctx);
<       EVP_PKEY_free(pkey);
<       if (!ok) {
<         throw XSECCryptoException(XSECCryptoException::RSAError,
<                                   "OpenSSL:RSA privateKeyDecrypt - Error "
<                                   "decrypting OAEP padded RSA encrypt");
<       }
<
<       decryptSize = (int)len;
---
>                                 (unsigned char *) inBuf,
718a737,763
>                                 tBuf,
>                                 mp_rsaKey,
>                                 RSA_NO_PADDING);
>             if (decryptSize < 0) {
>                 throw XSECCryptoException(XSECCryptoException::RSAError,
>                     "OpenSSL:RSA privateKeyDecrypt - Error doing raw
decrypt of RSA encrypted data");
>             }
>
>             // Clear out the "0"s at the front
>             int i;
>             for (i = 0; i < num && tBuf[i] == 0; ++i)
>                 --decryptSize;
>
>             decryptSize = RSA_padding_check_PKCS1_OAEP(plainBuf,
>                                                        maxOutLength,
>                                                        &tBuf[i],
>                                                        decryptSize,
>                                                        num,
>                                                        params,
>                                                        paramslen,
>                                                        evp_md,
>                                                        mgf_md);
>
>             if (decryptSize < 0) {
>                 throw XSECCryptoException(XSECCryptoException::RSAError,
>                     "OpenSSL:RSA privateKeyDecrypt - Error removing
OAEPadding");
>             }
720c765,766
<     } break;
---
>         }
>         break;
722,725c768,771
<     default:
<       throw XSECCryptoException(XSECCryptoException::RSAError,
<                                 "OpenSSL:RSA - Unknown padding method");
<   }
---
>     default :
>         throw XSECCryptoException(XSECCryptoException::RSAError,
>             "OpenSSL:RSA - Unknown padding method");
>     }
739c785
<   return decryptSize;
---
>     return decryptSize;
747,755c793,809
<     const unsigned char* inBuf, unsigned char* cipherBuf, unsigned int
inLength,
<     unsigned int maxOutLength, PaddingType padding, const XMLCh* hashURI,
<     const XMLCh* mgfURI, unsigned char* params, unsigned int paramslen)
const {
<   // Perform an encrypt
<   if (mp_rsaKey == NULL) {
<     throw XSECCryptoException(
<         XSECCryptoException::RSAError,
<         "OpenSSL:RSA - Attempt to encrypt data with empty key");
<   }
---
>         const unsigned char* inBuf,
>         unsigned char* cipherBuf,
>         unsigned int inLength,
>         unsigned int maxOutLength,
>         PaddingType padding,
>         const XMLCh* hashURI,
>         const XMLCh* mgfURI,
>         unsigned char* params,
>         unsigned int paramslen) const {
>
>     // Perform an encrypt
>     if (mp_rsaKey == NULL) {
>         throw XSECCryptoException(XSECCryptoException::RSAError,
>             "OpenSSL:RSA - Attempt to encrypt data with empty key");
>     }
>
>     int encryptSize;
757c811
<   int encryptSize;
---
>     switch (padding) {
759,760c813
<   switch (padding) {
<     case XSECCryptoKeyRSA::PAD_PKCS_1_5:
---
>     case XSECCryptoKeyRSA::PAD_PKCS_1_5 :
762c815
<       encryptSize = RSA_public_encrypt(inLength,
---
>         encryptSize = RSA_public_encrypt(inLength,
764c817
<                                        inBuf,
---
>                             inBuf,
766c819
<                                        (unsigned char*)inBuf,
---
>                             (unsigned char *) inBuf,
768c821,828
<                                        cipherBuf, mp_rsaKey,
RSA_PKCS1_PADDING);
---
>                             cipherBuf,
>                             mp_rsaKey,
>                             RSA_PKCS1_PADDING);
>
>         if (encryptSize < 0) {
>             throw XSECCryptoException(XSECCryptoException::RSAError,
>                 "OpenSSL:RSA publicKeyEncrypt - Error performing PKCS1_5
padded RSA encrypt");
>         }
770,857c830
<       if (encryptSize < 0) {
<         throw XSECCryptoException(XSECCryptoException::RSAError,
<                                   "OpenSSL:RSA publicKeyEncrypt - Error "
<                                   "performing PKCS1_5 padded RSA
encrypt");
<       }
<
<       break;
<
<     case XSECCryptoKeyRSA::PAD_OAEP: {
<       unsigned char* tBuf;
<       unsigned int num = RSA_size(mp_rsaKey);
<       if (maxOutLength < num) {
<         throw XSECCryptoException(
<             XSECCryptoException::RSAError,
<             "OpenSSL:RSA publicKeyEncrypt - Not enough space in
cipherBuf");
<       }
<
<       const EVP_MD* evp_md =
<
getDigestFromHashType(XSECAlgorithmSupport::getHashType(hashURI));
<       if (evp_md == NULL) {
<         throw XSECCryptoException(
<             XSECCryptoException::UnsupportedAlgorithm,
<             "OpenSSL:RSA - OAEP digest algorithm not supported");
<       }
<
<       const EVP_MD* mgf_md =
<
getDigestFromHashType(XSECAlgorithmSupport::getMGF1HashType(mgfURI));
<       if (mgf_md == NULL) {
<         throw XSECCryptoException(
<             XSECCryptoException::UnsupportedAlgorithm,
<             "OpenSSL:RSA - OAEP MGF algorithm not supported");
<       }
<
< #if OPENSSL_VERSION_NUMBER < 0x10002000
<       // Once OpenSSL 1.0.1 (EOL since December 2016) support is dropped,
this
<       // code may be removed.
<       XSECnew(tBuf, unsigned char[num]);
<       ArrayJanitor<unsigned char> j_tBuf(tBuf);
<
<       // First add the padding
<       encryptSize = RSA_padding_add_PKCS1_OAEP(
<           tBuf, num,
<           //#if defined(XSEC_OPENSSL_CONST_BUFFERS)
<           inBuf,
<           //#else
<           //                                                   (unsigned
char *)
<           //                                                   inBuf,
<           //#endif
<           inLength, params, paramslen, evp_md, mgf_md);
<
<       if (encryptSize <= 0) {
<         throw XSECCryptoException(
<             XSECCryptoException::RSAError,
<             "OpenSSL:RSA publicKeyEncrypt - Error adding OAEPadding");
<       }
<
<       encryptSize =
<           RSA_public_encrypt(num, tBuf, cipherBuf, mp_rsaKey,
RSA_NO_PADDING);
<       if (encryptSize < 0) {
<         throw XSECCryptoException(
<             XSECCryptoException::RSAError,
<             "OpenSSL:RSA publicKeyEncrypt - Error encrypting padded
data");
<       }
< #else
<       EVP_PKEY* pkey = EVP_PKEY_new();
<       if (pkey == NULL || EVP_PKEY_set1_RSA(pkey, mp_rsaKey) <= 0) {
<         EVP_PKEY_free(pkey);
<         throw XSECCryptoException(XSECCryptoException::RSAError,
<                                   "OpenSSL:RSA publicKeyEncrypt - Error "
<                                   "wrapping RSA key");
<       }
<
<       size_t len = maxOutLength;
<       EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new(pkey, NULL);
<       bool ok =
<           ctx != NULL &&
<           EVP_PKEY_encrypt_init(ctx) == 1 &&
<           EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) == 1
&&
<           EVP_PKEY_CTX_set_rsa_oaep_md(ctx, evp_md) == 1 &&
<           EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, mgf_md) == 1 &&
<           EVP_PKEY_encrypt(ctx, cipherBuf, &len, inBuf, inLength) == 1;
<       EVP_PKEY_CTX_free(ctx);
<       EVP_PKEY_free(pkey);
<       if (!ok) {
<         throw XSECCryptoException(XSECCryptoException::RSAError,
<                                   "OpenSSL:RSA publicKeyEncrypt - Error "
<                                   "performing OAEP padded RSA encrypt");
<       }
---
>         break;
859,861c832,886
<       encryptSize = (int)len;
< #endif
<     } break;
---
>     case XSECCryptoKeyRSA::PAD_OAEP :
>         {
>             unsigned char * tBuf;
>             unsigned int num = RSA_size(mp_rsaKey);
>             if (maxOutLength < num) {
>                 throw XSECCryptoException(XSECCryptoException::RSAError,
>                     "OpenSSL:RSA publicKeyEncrypt - Not enough space in
cipherBuf");
>             }
>
>             const EVP_MD* evp_md =
getDigestFromHashType(XSECAlgorithmSupport::getHashType(hashURI));
>             if (evp_md == NULL) {
>                 throw
XSECCryptoException(XSECCryptoException::UnsupportedAlgorithm,
>                     "OpenSSL:RSA - OAEP digest algorithm not supported");
>             }
>
>
>             const EVP_MD* mgf_md =
getDigestFromHashType(XSECAlgorithmSupport::getMGF1HashType(mgfURI));
>             if (mgf_md == NULL) {
>                 throw
XSECCryptoException(XSECCryptoException::UnsupportedAlgorithm,
>                     "OpenSSL:RSA - OAEP MGF algorithm not supported");
>             }
>
>             XSECnew(tBuf, unsigned char[num]);
>             ArrayJanitor<unsigned char> j_tBuf(tBuf);
>
>             // First add the padding
>             encryptSize = RSA_padding_add_PKCS1_OAEP(tBuf,
>                                                      num,
> //#if defined(XSEC_OPENSSL_CONST_BUFFERS)
>                                                      inBuf,
> //#else
> //                                                   (unsigned char *)
inBuf,
> //#endif
>                                                      inLength,
>                                                      params,
>                                                      paramslen,
>                                                      evp_md,
>                                                      mgf_md);
>
>             if (encryptSize <= 0) {
>                 throw XSECCryptoException(XSECCryptoException::RSAError,
>                     "OpenSSL:RSA publicKeyEncrypt - Error adding
OAEPadding");
>             }
>
>             encryptSize = RSA_public_encrypt(num,
>                                 tBuf,
>                                 cipherBuf,
>                                 mp_rsaKey,
>                                 RSA_NO_PADDING);
>             if (encryptSize < 0) {
>                 throw XSECCryptoException(XSECCryptoException::RSAError,
>                     "OpenSSL:RSA publicKeyEncrypt - Error encrypting
padded data");
>             }
>         }
>         break;
863,866c888,891
<     default:
<       throw XSECCryptoException(XSECCryptoException::RSAError,
<                                 "OpenSSL:RSA - Unknown padding method");
<   }
---
>     default :
>         throw XSECCryptoException(XSECCryptoException::RSAError,
>             "OpenSSL:RSA - Unknown padding method");
>     }
868c893
<   return encryptSize;
---
>     return encryptSize;
876d900
<   if (mp_rsaKey != NULL) return RSA_size(mp_rsaKey);
878c902,905
<   return 0;
---
>     if (mp_rsaKey != NULL)
>         return RSA_size(mp_rsaKey);
>
>     return 0;
885,886c912,918
< XSECCryptoKey* OpenSSLCryptoKeyRSA::clone() const {
<   OpenSSLCryptoKeyRSA* ret;
---
> XSECCryptoKey * OpenSSLCryptoKeyRSA::clone() const {
>
>     OpenSSLCryptoKeyRSA * ret;
>
>     XSECnew(ret, OpenSSLCryptoKeyRSA);
>
>     ret->mp_rsaKey = RSA_new();
888c920,924
<   XSECnew(ret, OpenSSLCryptoKeyRSA);
---
>     // Duplicate parameters
>     const BIGNUM *n=NULL, *e=NULL, *d=NULL;
>     RSA_get0_key(mp_rsaKey, &n, &e, &d);
>     if (n && e) // Do not dup unless setter will work
>         RSA_set0_key(ret->mp_rsaKey, DUP_NON_NULL(n), DUP_NON_NULL(e),
DUP_NON_NULL(d));
890c926,929
<   ret->mp_rsaKey = RSA_new();
---
>     const BIGNUM *p=NULL, *q=NULL;
>     RSA_get0_factors(mp_rsaKey, &p, &q);
>     if (p && q)
>         RSA_set0_factors(ret->mp_rsaKey, DUP_NON_NULL(p),
DUP_NON_NULL(q));
892,908c931,934
<   // Duplicate parameters
<   const BIGNUM *n = NULL, *e = NULL, *d = NULL;
<   RSA_get0_key(mp_rsaKey, &n, &e, &d);
<   if (n && e)  // Do not dup unless setter will work
<     RSA_set0_key(ret->mp_rsaKey, DUP_NON_NULL(n), DUP_NON_NULL(e),
<                  DUP_NON_NULL(d));
<
<   const BIGNUM *p = NULL, *q = NULL;
<   RSA_get0_factors(mp_rsaKey, &p, &q);
<   if (p && q)
<     RSA_set0_factors(ret->mp_rsaKey, DUP_NON_NULL(p), DUP_NON_NULL(q));
<
<   const BIGNUM *dmp1 = NULL, *dmq1 = NULL, *iqmp = NULL;
<   RSA_get0_crt_params(mp_rsaKey, &dmp1, &dmq1, &iqmp);
<   if (dmp1 && dmq1 && iqmp)
<     RSA_set0_crt_params(ret->mp_rsaKey, DUP_NON_NULL(dmp1),
DUP_NON_NULL(dmq1),
<                         DUP_NON_NULL(iqmp));
---
>     const BIGNUM *dmp1=NULL, *dmq1=NULL, *iqmp=NULL;
>     RSA_get0_crt_params(mp_rsaKey, &dmp1, &dmq1, &iqmp);
>     if (dmp1 && dmq1 && iqmp)
>         RSA_set0_crt_params(ret->mp_rsaKey, DUP_NON_NULL(dmp1),
DUP_NON_NULL(dmq1), DUP_NON_NULL(iqmp));
910c936
<   return ret;
---
>     return ret;

Re: [xml-security-c] Patch to use newer version of OpenSSL APIs for RSA OAEP

Posted by "Cantor, Scott" <ca...@osu.edu>.
There are no more releases of this code planned, but if you want the patch filed or if another committer emerges to do the work, please file it in Jira.

For the record, I would not disallow the use of the code on any OpenSSL version without a good reason, it's just needless breakage. Conditional patches that maintain the support back to the older versions are fine.

-- Scott