xsec/enc/OpenSSL/OpenSSLCryptoX509.cpp (131 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 * * OpenSSLCryptoX509:= OpenSSL based class for handling X509 (V3) certificates * * Author(s): Berin Lautenbach * * $Id$ * */ #include <xsec/framework/XSECDefs.hpp> #if defined (XSEC_HAVE_OPENSSL) #include <xsec/dsig/DSIGConstants.hpp> #include <xsec/framework/XSECError.hpp> #include <xsec/enc/OpenSSL/OpenSSLCryptoX509.hpp> #include <xsec/enc/OpenSSL/OpenSSLCryptoKeyDSA.hpp> #include <xsec/enc/OpenSSL/OpenSSLCryptoKeyEC.hpp> #include <xsec/enc/OpenSSL/OpenSSLCryptoKeyRSA.hpp> #include <xsec/enc/OpenSSL/OpenSSLSupport.hpp> #include <xsec/enc/XSECCryptoException.hpp> #include <xsec/enc/XSCrypt/XSCryptCryptoBase64.hpp> #include <xercesc/util/Janitor.hpp> XSEC_USING_XERCES(ArrayJanitor); XSEC_USING_XERCES(Janitor); #include <openssl/evp.h> OpenSSLCryptoX509::OpenSSLCryptoX509() : m_DERX509("") { mp_X509 = NULL; } OpenSSLCryptoX509::~OpenSSLCryptoX509() { if (mp_X509 != NULL) X509_free(mp_X509); } OpenSSLCryptoX509::OpenSSLCryptoX509(X509 * x) { // Build this from an existing X509 structure mp_X509 = X509_dup(x); // Now need to create the DER encoding 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 X509 to Base64 i2d_X509_bio(b64, x); BIO_flush(b64); char buf[1024]; unsigned int l; m_DERX509.sbStrcpyIn(""); while ((l = BIO_read(bmem, buf, 1023)) > 0) { buf[l] = '\0'; m_DERX509.sbStrcatIn(buf); } BIO_free_all(b64); } // load functions void OpenSSLCryptoX509::loadX509Base64Bin(const char * buf, unsigned int len) { // Free anything currently held. if (mp_X509 != NULL) X509_free(mp_X509); // Have to implement using EVP_Decode routines due to a bug in older // versions of OpenSSL BIO_f_base64 int bufLen = len; unsigned char * outBuf; XSECnew(outBuf, unsigned char[len + 1]); ArrayJanitor<unsigned char> j_outBuf(outBuf); /* Had to move to our own Base64 decoder because it handles non-wrapped b64 better. Grrr. */ XSCryptCryptoBase64 *b64; XSECnew(b64, XSCryptCryptoBase64); Janitor<XSCryptCryptoBase64> j_b64(b64); b64->decodeInit(); bufLen = b64->decode((unsigned char *) buf, len, outBuf, len); bufLen += b64->decodeFinish(&outBuf[bufLen], len-bufLen); /* EVP_ENCODE_CTX m_dctx; EVP_DecodeInit(&m_dctx); int rc = EVP_DecodeUpdate(&m_dctx, outBuf, &bufLen, (unsigned char *) buf, len); if (rc < 0) { throw XSECCryptoException(XSECCryptoException::Base64Error, "OpenSSL:Base64 - Error during Base64 Decode of X509 Certificate"); } int finalLen; EVP_DecodeFinal(&m_dctx, &outBuf[bufLen], &finalLen); bufLen += finalLen; */ if (bufLen > 0) { #if defined(XSEC_OPENSSL_D2IX509_CONST_BUFFER) mp_X509= d2i_X509(NULL, (const unsigned char **) (&outBuf), bufLen); #else mp_X509= d2i_X509(NULL, &outBuf, bufLen); #endif } // Check to see if we have a certificate.... if (mp_X509 == NULL) { throw XSECCryptoException(XSECCryptoException::X509Error, "OpenSSL:X509 - Error translating Base64 DER encoding into OpenSSL X509 structure"); } m_DERX509.sbMemcpyIn(buf, len); m_DERX509[len] = '\0'; } // Info functions const XMLCh * OpenSSLCryptoX509::getProviderName() const { return DSIGConstants::s_unicodeStrPROVOpenSSL; } XSECCryptoKey::KeyType OpenSSLCryptoX509::getPublicKeyType() const { if (mp_X509 == NULL) { throw XSECCryptoException(XSECCryptoException::X509Error, "OpenSSL:X509 - getPublicKeyType called before X509 loaded"); } EVP_PKEY *pkey; pkey = X509_get_pubkey(mp_X509); if (pkey == NULL) { throw XSECCryptoException(XSECCryptoException::X509Error, "OpenSSL:X509 - cannot retrieve public key from cert"); } XSECCryptoKey::KeyType ret; switch (EVP_PKEY_id(pkey)) { case EVP_PKEY_DSA : ret = XSECCryptoKey::KEY_DSA_PUBLIC; break; case EVP_PKEY_RSA : ret = XSECCryptoKey::KEY_RSA_PUBLIC; break; #if defined(XSEC_OPENSSL_HAVE_EC) case EVP_PKEY_EC : ret = XSECCryptoKey::KEY_EC_PUBLIC; break; #endif default : ret = XSECCryptoKey::KEY_NONE; } EVP_PKEY_free (pkey); return ret; } // Get functions XSECCryptoKey * OpenSSLCryptoX509::clonePublicKey() const { if (mp_X509 == NULL) { throw XSECCryptoException(XSECCryptoException::X509Error, "OpenSSL:X509 - clonePublicKey called before X509 loaded"); } EVP_PKEY *pkey; XSECCryptoKey * ret; pkey = X509_get_pubkey(mp_X509); if (pkey == NULL) { throw XSECCryptoException(XSECCryptoException::X509Error, "OpenSSL:X509 - cannot retrieve public key from cert"); } switch (EVP_PKEY_id(pkey)) { case EVP_PKEY_DSA : ret = new OpenSSLCryptoKeyDSA(pkey); break; case EVP_PKEY_RSA : ret = new OpenSSLCryptoKeyRSA(pkey); break; #if defined(XSEC_OPENSSL_HAVE_EC) case EVP_PKEY_EC : ret = new OpenSSLCryptoKeyEC(pkey); break; #endif default : ret = NULL; } EVP_PKEY_free (pkey); return ret; } #endif /* XSEC_HAVE_OPENSSL */