xsec/enc/OpenSSL/OpenSSLCryptoKeyRSA.cpp (646 lines of code) (raw):

/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /* * XSEC * * OpenSSLCryptoKeyRSA := RSA Keys * * Author(s): Berin Lautenbach * * $Id$ * */ #include <xsec/framework/XSECDefs.hpp> #if defined (XSEC_HAVE_OPENSSL) #include <xsec/enc/OpenSSL/OpenSSLCryptoKeyRSA.hpp> #include <xsec/enc/OpenSSL/OpenSSLCryptoBase64.hpp> #include <xsec/enc/OpenSSL/OpenSSLSupport.hpp> #include <xsec/enc/XSECCryptoException.hpp> #include <xsec/enc/XSECCryptoUtils.hpp> #include <xsec/framework/XSECError.hpp> #include "../../utils/XSECAlgorithmSupport.hpp" #include <openssl/err.h> #include <openssl/rand.h> #include <openssl/rsa.h> #include <openssl/sha.h> #include <xercesc/util/Janitor.hpp> XSEC_USING_XERCES(ArrayJanitor); #include <memory.h> namespace { // 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. #ifndef XSEC_OPENSSL_HAVE_MGF1 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; } #endif 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]; OPENSSL_free(dbmask); return 1; } 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; } }; const EVP_MD* getDigestFromHashType(XSECCryptoHash::HashType type) { const EVP_MD* evp_md = NULL; 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; default: ; } return evp_md; } OpenSSLCryptoKeyRSA::OpenSSLCryptoKeyRSA() : mp_rsaKey(NULL), mp_accumE(NULL), mp_accumN(NULL) { }; OpenSSLCryptoKeyRSA::~OpenSSLCryptoKeyRSA() { // If we have a RSA, delete it (OpenSSL will clear the memory) if (mp_rsaKey) RSA_free(mp_rsaKey); if (mp_accumE) BN_free(mp_accumE); if (mp_accumN) BN_free(mp_accumN); }; const XMLCh* OpenSSLCryptoKeyRSA::getProviderName() const { return DSIGConstants::s_unicodeStrPROVOpenSSL; } // Generic key functions XSECCryptoKey::KeyType OpenSSLCryptoKeyRSA::getKeyType() const { // Find out what we have if (mp_rsaKey == NULL) return KEY_NONE; const BIGNUM *n, *d; RSA_get0_key(mp_rsaKey, &n, NULL, &d); if (n != NULL && d != NULL) return KEY_RSA_PAIR; if (d != NULL) return KEY_RSA_PRIVATE; if (n != NULL) return KEY_RSA_PUBLIC; return KEY_NONE; } void OpenSSLCryptoKeyRSA::loadPublicModulusBase64BigNums(const char* b64, unsigned int len) { setNBase(OpenSSLCryptoBase64::b642BN((char *) b64, len)); } void OpenSSLCryptoKeyRSA::setNBase(BIGNUM *nBase) { if (mp_rsaKey == NULL) mp_rsaKey = RSA_new(); #if (OPENSSL_VERSION_NUMBER < 0x10100000L) mp_rsaKey->n = nBase; #else if (mp_accumN) BN_free(mp_accumN); mp_accumN = nBase; commitEN(); #endif } void OpenSSLCryptoKeyRSA::loadPublicExponentBase64BigNums(const char* b64, unsigned int len) { setEBase(OpenSSLCryptoBase64::b642BN((char *) b64, len)); } void OpenSSLCryptoKeyRSA::setEBase(BIGNUM *eBase) { if (mp_rsaKey == NULL) mp_rsaKey = RSA_new(); #if (OPENSSL_VERSION_NUMBER < 0x10100000L) mp_rsaKey->e = eBase; #else if (mp_accumE) BN_free(mp_accumE); mp_accumE = eBase; commitEN(); #endif } #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) void OpenSSLCryptoKeyRSA::commitEN() { if (NULL == mp_accumN || NULL == mp_accumE) return; RSA_set0_key(mp_rsaKey, mp_accumN, mp_accumE, NULL); mp_accumN = NULL; mp_accumE = NULL; } #endif // "Hidden" OpenSSL functions 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 const 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)); } // -------------------------------------------------------------------------------- // Verify a signature encoded as a Base64 string // -------------------------------------------------------------------------------- bool OpenSSLCryptoKeyRSA::verifySHA1PKCS1Base64Signature( 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; } } // All OK return true; } // -------------------------------------------------------------------------------- // Sign and encode result as a Base64 string // -------------------------------------------------------------------------------- unsigned int OpenSSLCryptoKeyRSA::signSHA1PKCS1Base64Signature( 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); // 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"); } // Now convert to Base 64 BIO * b64 = BIO_new(BIO_f_base64()); BIO * bmem = BIO_new(BIO_s_mem()); BIO_set_mem_eof_return(bmem, 0); b64 = BIO_push(b64, bmem); // Translate signature to Base64 BIO_write(b64, encryptBuf, encryptLen); BIO_flush(b64); unsigned int sigValLen = BIO_read(bmem, base64SignatureBuf, base64SignatureBufLen); BIO_free_all(b64); delete[] encryptBuf; if (sigValLen <= 0) { throw XSECCryptoException(XSECCryptoException::DSAError, "OpenSSL:RSA - Error base64 encoding signature"); } return sigValLen; } // -------------------------------------------------------------------------------- // decrypt a buffer // -------------------------------------------------------------------------------- unsigned int OpenSSLCryptoKeyRSA::privateDecrypt( 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"); } #if 0 /* normally commented out code to determine endian problems */ unsigned int i; unsigned char e[2048]; unsigned char * inBuf1 = (unsigned char *) inBuf; if (inLength < 2048) { memcpy(e, inBuf, inLength); for (i = 0; i < inLength;++i) { inBuf1[i] = e[inLength - 1 - i]; } } #endif int decryptSize; switch (padding) { case XSECCryptoKeyRSA::PAD_PKCS_1_5 : decryptSize = RSA_private_decrypt(inLength, #if defined(XSEC_OPENSSL_CONST_BUFFERS) inBuf, #else (unsigned char *) inBuf, #endif plainBuf, mp_rsaKey, RSA_PKCS1_PADDING); 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"); } unsigned char * tBuf; int num = RSA_size(mp_rsaKey); XSECnew(tBuf, unsigned char[num]); ArrayJanitor<unsigned char> j_tBuf(tBuf); decryptSize = RSA_private_decrypt(inLength, #if defined(XSEC_OPENSSL_CONST_BUFFERS) 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"); } } break; default : throw XSECCryptoException(XSECCryptoException::RSAError, "OpenSSL:RSA - Unknown padding method"); } #if 0 /* normally commented out code to determine endian problems */ int i; unsigned char t[512]; if (decryptSize < 512) { memcpy(t, plainBuf, decryptSize); for (i = 0; i < decryptSize;++i) { plainBuf[i] = t[decryptSize - 1 - i]; } } #endif return decryptSize; } // -------------------------------------------------------------------------------- // encrypt a buffer // -------------------------------------------------------------------------------- unsigned int OpenSSLCryptoKeyRSA::publicEncrypt( 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; switch (padding) { case XSECCryptoKeyRSA::PAD_PKCS_1_5 : encryptSize = RSA_public_encrypt(inLength, #if defined(XSEC_OPENSSL_CONST_BUFFERS) inBuf, #else (unsigned char *) inBuf, #endif cipherBuf, mp_rsaKey, RSA_PKCS1_PADDING); 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"); } 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; default : throw XSECCryptoException(XSECCryptoException::RSAError, "OpenSSL:RSA - Unknown padding method"); } return encryptSize; } // -------------------------------------------------------------------------------- // Size in bytes // -------------------------------------------------------------------------------- unsigned int OpenSSLCryptoKeyRSA::getLength() const { if (mp_rsaKey != NULL) return RSA_size(mp_rsaKey); return 0; } // -------------------------------------------------------------------------------- // Clone this key // -------------------------------------------------------------------------------- XSECCryptoKey * OpenSSLCryptoKeyRSA::clone() const { OpenSSLCryptoKeyRSA * ret; XSECnew(ret, OpenSSLCryptoKeyRSA); ret->mp_rsaKey = RSA_new(); // 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)); return ret; } #endif /* XSEC_HAVE_OPENSSL */