1 /**
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 
20 /*
21  * XSEC
22  *
23  * OpenSSLCryptoX509:= OpenSSL based class for handling X509 (V3) certificates
24  *
25  * Author(s): Berin Lautenbach
26  *
27  * $Id: OpenSSLCryptoX509.cpp 1817971 2017-12-13 02:23:51Z scantor $
28  *
29  */
30 
31 #include <xsec/framework/XSECDefs.hpp>
32 
33 #if defined (XSEC_HAVE_OPENSSL)
34 
35 #include <xsec/dsig/DSIGConstants.hpp>
36 #include <xsec/framework/XSECError.hpp>
37 #include <xsec/enc/OpenSSL/OpenSSLCryptoX509.hpp>
38 #include <xsec/enc/OpenSSL/OpenSSLCryptoKeyDSA.hpp>
39 #include <xsec/enc/OpenSSL/OpenSSLCryptoKeyEC.hpp>
40 #include <xsec/enc/OpenSSL/OpenSSLCryptoKeyRSA.hpp>
41 #include <xsec/enc/OpenSSL/OpenSSLSupport.hpp>
42 #include <xsec/enc/XSECCryptoException.hpp>
43 #include <xsec/enc/XSCrypt/XSCryptCryptoBase64.hpp>
44 
45 #include <xercesc/util/Janitor.hpp>
46 
47 XSEC_USING_XERCES(ArrayJanitor);
48 XSEC_USING_XERCES(Janitor);
49 
50 #include <openssl/evp.h>
51 
OpenSSLCryptoX509()52 OpenSSLCryptoX509::OpenSSLCryptoX509() :
53 m_DERX509("") {
54 
55     mp_X509 = NULL;
56 
57 }
58 
~OpenSSLCryptoX509()59 OpenSSLCryptoX509::~OpenSSLCryptoX509() {
60 
61     if (mp_X509 != NULL)
62         X509_free(mp_X509);
63 
64 }
65 
OpenSSLCryptoX509(X509 * x)66 OpenSSLCryptoX509::OpenSSLCryptoX509(X509 * x) {
67 
68     // Build this from an existing X509 structure
69 
70     mp_X509 = X509_dup(x);
71 
72     // Now need to create the DER encoding
73 
74     BIO * b64 = BIO_new(BIO_f_base64());
75     BIO * bmem = BIO_new(BIO_s_mem());
76 
77     BIO_set_mem_eof_return(bmem, 0);
78     b64 = BIO_push(b64, bmem);
79 
80     // Translate X509 to Base64
81 
82     i2d_X509_bio(b64, x);
83 
84     BIO_flush(b64);
85 
86     char buf[1024];
87     unsigned int l;
88 
89     m_DERX509.sbStrcpyIn("");
90 
91     while ((l = BIO_read(bmem, buf, 1023)) > 0) {
92         buf[l] = '\0';
93         m_DERX509.sbStrcatIn(buf);
94     }
95 
96     BIO_free_all(b64);
97 
98 }
99 
100 // load functions
101 
loadX509Base64Bin(const char * buf,unsigned int len)102 void OpenSSLCryptoX509::loadX509Base64Bin(const char * buf, unsigned int len) {
103 
104     // Free anything currently held.
105 
106     if (mp_X509 != NULL)
107         X509_free(mp_X509);
108 
109     // Have to implement using EVP_Decode routines due to a bug in older
110     // versions of OpenSSL BIO_f_base64
111 
112     int bufLen = len;
113     unsigned char * outBuf;
114     XSECnew(outBuf, unsigned char[len + 1]);
115     ArrayJanitor<unsigned char> j_outBuf(outBuf);
116 
117     /* Had to move to our own Base64 decoder because it handles non-wrapped b64
118        better.  Grrr. */
119 
120     XSCryptCryptoBase64 *b64;
121     XSECnew(b64, XSCryptCryptoBase64);
122     Janitor<XSCryptCryptoBase64> j_b64(b64);
123 
124     b64->decodeInit();
125     bufLen = b64->decode((unsigned char *) buf, len, outBuf, len);
126     bufLen += b64->decodeFinish(&outBuf[bufLen], len-bufLen);
127 
128     /*
129 
130     EVP_ENCODE_CTX m_dctx;
131     EVP_DecodeInit(&m_dctx);
132 
133     int rc = EVP_DecodeUpdate(&m_dctx,
134                           outBuf,
135                           &bufLen,
136                           (unsigned char *) buf,
137                           len);
138 
139     if (rc < 0) {
140 
141         throw XSECCryptoException(XSECCryptoException::Base64Error,
142             "OpenSSL:Base64 - Error during Base64 Decode of X509 Certificate");
143     }
144 
145     int finalLen;
146     EVP_DecodeFinal(&m_dctx, &outBuf[bufLen], &finalLen);
147 
148     bufLen += finalLen;
149     */
150     if (bufLen > 0) {
151 #if defined(XSEC_OPENSSL_D2IX509_CONST_BUFFER)
152         mp_X509=  d2i_X509(NULL, (const unsigned char **) (&outBuf), bufLen);
153 #else
154         mp_X509=  d2i_X509(NULL, &outBuf, bufLen);
155 #endif
156     }
157 
158     // Check to see if we have a certificate....
159     if (mp_X509 == NULL) {
160 
161         throw XSECCryptoException(XSECCryptoException::X509Error,
162         "OpenSSL:X509 - Error translating Base64 DER encoding into OpenSSL X509 structure");
163 
164     }
165 
166     m_DERX509.sbStrcpyIn(buf);
167 
168 }
169 
170 // Info functions
171 
getProviderName() const172 const XMLCh * OpenSSLCryptoX509::getProviderName() const {
173 
174     return DSIGConstants::s_unicodeStrPROVOpenSSL;
175 
176 }
177 
getPublicKeyType() const178 XSECCryptoKey::KeyType OpenSSLCryptoX509::getPublicKeyType() const {
179 
180     if (mp_X509 == NULL) {
181         throw XSECCryptoException(XSECCryptoException::X509Error,
182             "OpenSSL:X509 - getPublicKeyType called before X509 loaded");
183     }
184 
185     EVP_PKEY *pkey;
186 
187     pkey = X509_get_pubkey(mp_X509);
188 
189     if (pkey == NULL) {
190         throw XSECCryptoException(XSECCryptoException::X509Error,
191             "OpenSSL:X509 - cannot retrieve public key from cert");
192     }
193 
194     XSECCryptoKey::KeyType ret;
195 
196     switch (EVP_PKEY_id(pkey)) {
197 
198     case EVP_PKEY_DSA :
199 
200         ret = XSECCryptoKey::KEY_DSA_PUBLIC;
201         break;
202 
203     case EVP_PKEY_RSA :
204 
205         ret = XSECCryptoKey::KEY_RSA_PUBLIC;
206         break;
207 
208 #if defined(XSEC_OPENSSL_HAVE_EC)
209     case EVP_PKEY_EC :
210 
211         ret = XSECCryptoKey::KEY_EC_PUBLIC;
212         break;
213 #endif
214 
215     default :
216 
217         ret = XSECCryptoKey::KEY_NONE;
218 
219     }
220 
221     EVP_PKEY_free (pkey);
222 
223     return ret;
224 
225 }
226 
227 
228 // Get functions
clonePublicKey() const229 XSECCryptoKey * OpenSSLCryptoX509::clonePublicKey() const {
230 
231     if (mp_X509 == NULL) {
232         throw XSECCryptoException(XSECCryptoException::X509Error,
233             "OpenSSL:X509 - clonePublicKey called before X509 loaded");
234     }
235 
236     EVP_PKEY *pkey;
237     XSECCryptoKey * ret;
238 
239     pkey = X509_get_pubkey(mp_X509);
240 
241     if (pkey == NULL) {
242         throw XSECCryptoException(XSECCryptoException::X509Error,
243             "OpenSSL:X509 - cannot retrieve public key from cert");
244     }
245 
246     switch (EVP_PKEY_id(pkey)) {
247 
248     case EVP_PKEY_DSA :
249 
250         ret = new OpenSSLCryptoKeyDSA(pkey);
251         break;
252 
253     case EVP_PKEY_RSA :
254 
255         ret = new OpenSSLCryptoKeyRSA(pkey);
256         break;
257 
258 #if defined(XSEC_OPENSSL_HAVE_EC)
259     case EVP_PKEY_EC :
260 
261         ret = new OpenSSLCryptoKeyEC(pkey);
262         break;
263 #endif
264 
265     default :
266 
267         ret = NULL;
268 
269     }
270 
271     EVP_PKEY_free (pkey);
272 
273     return ret;
274 
275 }
276 
277 #endif /* XSEC_HAVE_OPENSSL */
278