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