Implemented X.509 certificate reading using OpenSSL
[strongswan.git] / src / libstrongswan / plugins / openssl / openssl_util.c
1 /*
2 * Copyright (C) 2009 Martin Willi
3 * Copyright (C) 2008 Tobias Brunner
4 * Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #include "openssl_util.h"
18
19 #include <debug.h>
20
21 #include <openssl/evp.h>
22 #include <openssl/x509.h>
23
24 /**
25 * Described in header.
26 */
27 bool openssl_hash_chunk(int hash_type, chunk_t data, chunk_t *hash)
28 {
29 EVP_MD_CTX *ctx;
30 bool ret = FALSE;
31 const EVP_MD *hasher = EVP_get_digestbynid(hash_type);
32 if (!hasher)
33 {
34 return FALSE;
35 }
36
37 ctx = EVP_MD_CTX_create();
38 if (!ctx)
39 {
40 goto error;
41 }
42
43 if (!EVP_DigestInit_ex(ctx, hasher, NULL))
44 {
45 goto error;
46 }
47
48 if (!EVP_DigestUpdate(ctx, data.ptr, data.len))
49 {
50 goto error;
51 }
52
53 *hash = chunk_alloc(hasher->md_size);
54 if (!EVP_DigestFinal_ex(ctx, hash->ptr, NULL))
55 {
56 chunk_free(hash);
57 goto error;
58 }
59
60 ret = TRUE;
61 error:
62 if (ctx)
63 {
64 EVP_MD_CTX_destroy(ctx);
65 }
66 return ret;
67 }
68
69 /**
70 * Described in header.
71 */
72 bool openssl_bn_cat(int len, BIGNUM *a, BIGNUM *b, chunk_t *chunk)
73 {
74 int offset;
75
76 chunk->len = len + (b ? len : 0);
77 chunk->ptr = malloc(chunk->len);
78 memset(chunk->ptr, 0, chunk->len);
79
80 /* convert a */
81 offset = len - BN_num_bytes(a);
82 if (!BN_bn2bin(a, chunk->ptr + offset))
83 {
84 goto error;
85 }
86
87 /* optionally convert and concatenate b */
88 if (b)
89 {
90 offset = len - BN_num_bytes(b);
91 if (!BN_bn2bin(b, chunk->ptr + len + offset))
92 {
93 goto error;
94 }
95 }
96
97 return TRUE;
98 error:
99 chunk_free(chunk);
100 return FALSE;
101 }
102
103 /**
104 * Described in header.
105 */
106 bool openssl_bn_split(chunk_t chunk, BIGNUM *a, BIGNUM *b)
107 {
108 int len;
109
110 if ((chunk.len % 2) != 0)
111 {
112 return FALSE;
113 }
114
115 len = chunk.len / 2;
116
117 if (!BN_bin2bn(chunk.ptr, len, a) ||
118 !BN_bin2bn(chunk.ptr + len, len, b))
119 {
120 return FALSE;
121 }
122
123 return TRUE;
124 }
125
126 /**
127 * Described in header.
128 */
129 chunk_t openssl_asn1_obj2chunk(ASN1_OBJECT *asn1)
130 {
131 if (asn1)
132 {
133 return chunk_create(asn1->data, asn1->length);
134 }
135 return chunk_empty;
136 }
137
138 /**
139 * Described in header.
140 */
141 chunk_t openssl_asn1_str2chunk(ASN1_STRING *asn1)
142 {
143 if (asn1)
144 {
145 return chunk_create(ASN1_STRING_data(asn1), ASN1_STRING_length(asn1));
146 }
147 return chunk_empty;
148 }
149
150 /**
151 * Convert a X509 name to a ID_DER_ASN1_DN identification_t
152 */
153 identification_t *openssl_x509_name2id(X509_NAME *name)
154 {
155 if (name)
156 {
157 identification_t *id;
158 chunk_t chunk;
159
160 chunk = openssl_i2chunk(X509_NAME, name);
161 if (chunk.len)
162 {
163 id = identification_create_from_encoding(ID_DER_ASN1_DN, chunk);
164 free(chunk.ptr);
165 return id;
166 }
167 }
168 return NULL;
169 }
170
171 /**
172 * We can't include <asn1/asn1.h>, as the ASN1_ definitions would clash
173 * with OpenSSL. Redeclare what we need.
174 */
175 int asn1_known_oid(chunk_t);
176 time_t asn1_to_time(chunk_t *,int);
177
178 /**
179 * Described in header.
180 */
181 int openssl_asn1_known_oid(ASN1_OBJECT *obj)
182 {
183 return asn1_known_oid(openssl_asn1_obj2chunk(obj));
184 }
185
186 /**
187 * Described in header.
188 */
189 time_t openssl_asn1_to_time(ASN1_TIME *time)
190 {
191 chunk_t chunk;
192
193 if (time)
194 {
195 chunk = openssl_asn1_str2chunk(time);
196 switch (time->type)
197 {
198 case V_ASN1_UTCTIME:
199 case V_ASN1_GENERALIZEDTIME:
200 return asn1_to_time(&chunk, time->type);
201 default:
202 break;
203 }
204 }
205 DBG1(DBG_LIB, "invalid ASN1 time");
206 return 0;
207 }