Stefan Seyfried <seife+obs@b1-systems.com>
[vpnc.git] / crypto-openssl.c
blob9d98f8cf2910676f036376f32355b8b02167ddc5
1 /* IPSec VPN client compatible with Cisco equipment.
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2 of the License, or
6 (at your option) any later version.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <errno.h>
22 #include <openssl/pem.h>
23 #include "config.h"
24 #include "sysdep.h"
25 #include "crypto.h"
27 crypto_ctx *crypto_ctx_new(crypto_error **error)
29 crypto_ctx *ctx;
31 ctx = malloc(sizeof(crypto_ctx));
32 if (!ctx) {
33 crypto_error_set(error, 1, ENOMEM,
34 "not enough memory for crypto context");
35 return NULL;
38 OpenSSL_add_all_ciphers();
39 OpenSSL_add_all_digests();
40 OpenSSL_add_all_algorithms();
41 ERR_load_crypto_strings();
43 memset(ctx, 0, sizeof(crypto_ctx));
44 ctx->stack = sk_X509_new_null();
45 if (!ctx->stack) {
46 crypto_ctx_free(ctx);
47 crypto_error_set(error, 1, ENOMEM,
48 "not enough memory for crypto certificate stack");
49 ctx = NULL;
52 return ctx;
55 void crypto_ctx_free(crypto_ctx *ctx)
57 if (ctx) {
58 if (ctx->stack)
59 sk_X509_free(ctx->stack);
61 memset(ctx, 0, sizeof(crypto_ctx));
62 free(ctx);
66 static int password_cb(char *buf, int size, int rwflag, void *userdata)
68 /* Dummy callback to ensure openssl doesn't prompt for a password */
69 return 0;
72 unsigned char *crypto_read_cert(const char *path,
73 size_t *out_len,
74 crypto_error **error)
76 FILE *fp;
77 X509 *cert = NULL;
78 unsigned char *data = NULL, *p;
80 fp = fopen(path, "r");
81 if (!fp) {
82 crypto_error_set(error, 1, 0, "certificate (%s) could not be opened", path);
83 return NULL;
86 cert = PEM_read_X509(fp, NULL, password_cb, NULL);
87 fclose (fp);
89 if (!cert) {
90 /* Try DER then */
91 p = data = crypto_read_file(path, out_len, error);
92 if (!data || !*out_len) {
93 crypto_error_set(error, 1, 0, "could not read certificate %s", path);
94 return NULL;
97 cert = d2i_X509(NULL, (const unsigned char **) &p, (int) (*out_len));
98 if (!cert) {
99 free(data);
100 crypto_error_set(error, 1, 0, "could not allocate memory for certificate");
101 return NULL;
104 return data;
107 /* Get length of DER data */
108 *out_len = i2d_X509(cert, NULL);
109 if (!*out_len) {
110 crypto_error_set(error, 1, 0, "invalid certificate length");
111 goto out;
114 p = data = malloc(*out_len);
115 if (!data) {
116 crypto_error_set(error, 1, 0, "could not allocate memory for certificate");
117 goto out;
120 /* Encode the certificate to DER */
121 *out_len = i2d_X509(cert, &p);
122 if (!*out_len) {
123 crypto_error_set(error, 1, 0, "could not export certificate data");
124 if (data) {
125 free(data);
126 data = NULL;
128 goto out;
131 out:
132 if (cert)
133 X509_free(cert);
134 return data;
137 int crypto_push_cert(crypto_ctx *ctx,
138 const unsigned char *data,
139 size_t len,
140 crypto_error **error)
142 X509 *cert = NULL;
144 if (!ctx || !data || (len <= 0)) {
145 crypto_error_set(error, 1, 0, "invalid crypto context or data");
146 return 1;
149 /* convert the certificate to an openssl-X509 structure and push it onto the chain stack */
150 cert = d2i_X509(NULL, &data, (int) len);
151 if (!cert) {
152 ERR_print_errors_fp(stderr);
153 crypto_error_set(error, 1, 0, "failed to decode certificate");
154 return 1;
156 sk_X509_push(ctx->stack, cert);
157 return 0;
160 int crypto_verify_chain(crypto_ctx *ctx,
161 const char *ca_file,
162 const char *ca_dir,
163 crypto_error **error)
165 X509 *x509;
166 X509_STORE *store = NULL;
167 X509_LOOKUP *lookup = NULL;
168 X509_STORE_CTX *verify_ctx = NULL;
169 int ret = 1;
171 if (!ctx) {
172 crypto_error_set(error, 1, 0, "invalid crypto context");
173 return 1;
176 x509 = sk_X509_value(ctx->stack, sk_X509_num(ctx->stack) - 1);
177 if (x509 == NULL) {
178 ERR_print_errors_fp (stderr);
179 crypto_error_set(error, 1, 0, "no certificates in the stack");
180 return 1;
183 /* BEGIN - verify certificate chain */
184 /* create the cert store */
185 if (!(store = X509_STORE_new())) {
186 crypto_error_set(error, 1, 0, "error creating X509_STORE object");
187 return 1;
189 /* load the CA certificates */
190 if (X509_STORE_load_locations (store, ca_file, ca_dir) != 1) {
191 crypto_error_set(error, 1, 0, "error loading the CA file (%s) "
192 "or directory (%s)", ca_file, ca_dir);
193 goto out;
195 if (X509_STORE_set_default_paths (store) != 1) {
196 crypto_error_set(error, 1, 0, "error loading the system-wide CA"
197 " certificates");
198 goto out;
201 #if 0
202 /* check CRLs */
203 /* add the corresponding CRL for each CA in the chain to the lookup */
204 #define CRL_FILE "root-ca-crl.crl.pem"
206 if (!(lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()))) {
207 crypto_error_set(error, 1, 0, "error creating X509 lookup object.");
208 goto out;
210 if (X509_load_crl_file(lookup, CRL_FILE, X509_FILETYPE_PEM) != 1) {
211 ERR_print_errors_fp(stderr);
212 crypto_error_set(error, 1, 0, "error reading CRL file");
213 goto out;
215 X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
216 #endif /* 0 */
218 /* create a verification context and initialize it */
219 if (!(verify_ctx = X509_STORE_CTX_new ())) {
220 crypto_error_set(error, 1, 0, "error creating X509_STORE_CTX object");
221 goto out;
223 /* X509_STORE_CTX_init did not return an error condition in prior versions */
224 if (X509_STORE_CTX_init (verify_ctx, store, x509, ctx->stack) != 1) {
225 crypto_error_set(error, 1, 0, "error intializing verification context");
226 goto out;
229 /* verify the certificate */
230 if (X509_verify_cert(verify_ctx) != 1) {
231 ERR_print_errors_fp(stderr);
232 crypto_error_set(error, 2, 0, "error verifying the certificate "
233 "chain");
234 goto out;
237 ret = 0;
239 out:
240 if (lookup)
241 X509_LOOKUP_free(lookup);
242 if (store)
243 X509_STORE_free(store);
244 if (verify_ctx)
245 X509_STORE_CTX_free(verify_ctx);
246 return ret;
249 unsigned char *crypto_decrypt_signature(crypto_ctx *ctx,
250 const unsigned char *sig_data,
251 size_t sig_len,
252 size_t *out_len,
253 unsigned int padding,
254 crypto_error **error)
256 X509 *x509;
257 EVP_PKEY *pkey = NULL;
258 RSA *rsa;
259 unsigned char *hash = NULL;
260 int tmp_len = -1, ossl_pad;
262 *out_len = 0;
264 if (!ctx) {
265 crypto_error_set(error, 1, 0, "invalid crypto context");
266 return NULL;
269 x509 = sk_X509_value(ctx->stack, sk_X509_num(ctx->stack) - 1);
270 if (x509 == NULL) {
271 ERR_print_errors_fp (stderr);
272 crypto_error_set(error, 1, 0, "no certificates in the stack");
273 return NULL;
276 pkey = X509_get_pubkey(x509);
277 if (pkey == NULL) {
278 ERR_print_errors_fp (stderr);
279 crypto_error_set(error, 1, 0, "error getting certificate public key");
280 return NULL;
283 rsa = EVP_PKEY_get1_RSA(pkey);
284 if (rsa == NULL) {
285 ERR_print_errors_fp (stderr);
286 crypto_error_set(error, 1, 0, "error getting public key RSA");
287 goto out;
290 hash = calloc(1, RSA_size(rsa));
291 if (!hash) {
292 crypto_error_set(error, 1, 0, "not enough memory to decrypt signature");
293 goto out;
296 switch (padding) {
297 case CRYPTO_PAD_NONE:
298 ossl_pad = RSA_NO_PADDING;
299 break;
300 case CRYPTO_PAD_PKCS1:
301 ossl_pad = RSA_PKCS1_PADDING;
302 break;
303 default:
304 crypto_error_set(error, 1, 0, "unknown padding mechanism %d", padding);
305 goto out;
308 tmp_len = RSA_public_decrypt(sig_len, sig_data, hash, rsa, ossl_pad);
309 if (tmp_len > 0) {
310 *out_len = (size_t) tmp_len;
311 } else {
312 ERR_print_errors_fp (stderr);
313 crypto_error_set(error, 1, 0, "could not decrypt signature");
314 free(hash);
315 hash = NULL;
318 out:
319 if (pkey)
320 EVP_PKEY_free(pkey);
321 return hash;