blob: 342ad965142db93c31da330592816e0a71a05d4d [file] [log] [blame]
/**
* 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.sbStrcpyIn(buf);
}
// 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 */