a1d675f7814a3c473e753db08b609c7f24916fd5
[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 <utils/debug.h>
20
21 #include <openssl/bn.h>
22 #include <openssl/evp.h>
23 #include <openssl/x509.h>
24
25 /* these were added with 1.1.0 when ASN1_OBJECT was made opaque */
26 #if OPENSSL_VERSION_NUMBER < 0x10100000L
27 #define OBJ_get0_data(o) ((o)->data)
28 #define OBJ_length(o) ((o)->length)
29 #endif
30
31 /**
32 * Described in header.
33 */
34 bool openssl_hash_chunk(int hash_type, chunk_t data, chunk_t *hash)
35 {
36 EVP_MD_CTX *ctx;
37 bool ret = FALSE;
38 const EVP_MD *hasher = EVP_get_digestbynid(hash_type);
39 if (!hasher)
40 {
41 return FALSE;
42 }
43
44 ctx = EVP_MD_CTX_create();
45 if (!ctx)
46 {
47 goto error;
48 }
49
50 if (!EVP_DigestInit_ex(ctx, hasher, NULL))
51 {
52 goto error;
53 }
54
55 if (!EVP_DigestUpdate(ctx, data.ptr, data.len))
56 {
57 goto error;
58 }
59
60 *hash = chunk_alloc(EVP_MD_size(hasher));
61 if (!EVP_DigestFinal_ex(ctx, hash->ptr, NULL))
62 {
63 chunk_free(hash);
64 goto error;
65 }
66
67 ret = TRUE;
68 error:
69 if (ctx)
70 {
71 EVP_MD_CTX_destroy(ctx);
72 }
73 return ret;
74 }
75
76 /**
77 * Described in header.
78 */
79 bool openssl_bn_cat(int len, BIGNUM *a, BIGNUM *b, chunk_t *chunk)
80 {
81 int offset;
82
83 chunk->len = len + (b ? len : 0);
84 chunk->ptr = malloc(chunk->len);
85 memset(chunk->ptr, 0, chunk->len);
86
87 /* convert a */
88 offset = len - BN_num_bytes(a);
89 if (!BN_bn2bin(a, chunk->ptr + offset))
90 {
91 goto error;
92 }
93
94 /* optionally convert and concatenate b */
95 if (b)
96 {
97 offset = len - BN_num_bytes(b);
98 if (!BN_bn2bin(b, chunk->ptr + len + offset))
99 {
100 goto error;
101 }
102 }
103
104 return TRUE;
105 error:
106 chunk_free(chunk);
107 return FALSE;
108 }
109
110 /**
111 * Described in header.
112 */
113 bool openssl_bn_split(chunk_t chunk, BIGNUM *a, BIGNUM *b)
114 {
115 int len;
116
117 if ((chunk.len % 2) != 0)
118 {
119 return FALSE;
120 }
121
122 len = chunk.len / 2;
123
124 if (!BN_bin2bn(chunk.ptr, len, a) ||
125 !BN_bin2bn(chunk.ptr + len, len, b))
126 {
127 return FALSE;
128 }
129
130 return TRUE;
131 }
132
133 /**
134 * Described in header.
135 */
136 bool openssl_bn2chunk(BIGNUM *bn, chunk_t *chunk)
137 {
138 *chunk = chunk_alloc(BN_num_bytes(bn));
139 if (BN_bn2bin(bn, chunk->ptr) == chunk->len)
140 {
141 if (chunk->len && chunk->ptr[0] & 0x80)
142 { /* if MSB is set, prepend a zero to make it non-negative */
143 *chunk = chunk_cat("cm", chunk_from_chars(0x00), *chunk);
144 }
145 return TRUE;
146 }
147 chunk_free(chunk);
148 return FALSE;
149 }
150
151 /**
152 * Described in header.
153 */
154 chunk_t openssl_asn1_obj2chunk(ASN1_OBJECT *asn1)
155 {
156 if (asn1)
157 {
158 return chunk_create((u_char*)OBJ_get0_data(asn1), OBJ_length(asn1));
159 }
160 return chunk_empty;
161 }
162
163 /**
164 * Described in header.
165 */
166 chunk_t openssl_asn1_str2chunk(ASN1_STRING *asn1)
167 {
168 if (asn1)
169 {
170 return chunk_create(ASN1_STRING_data(asn1), ASN1_STRING_length(asn1));
171 }
172 return chunk_empty;
173 }
174
175 /**
176 * Convert a X509 name to a ID_DER_ASN1_DN identification_t
177 */
178 identification_t *openssl_x509_name2id(X509_NAME *name)
179 {
180 if (name)
181 {
182 identification_t *id;
183 chunk_t chunk;
184
185 chunk = openssl_i2chunk(X509_NAME, name);
186 if (chunk.len)
187 {
188 id = identification_create_from_encoding(ID_DER_ASN1_DN, chunk);
189 free(chunk.ptr);
190 return id;
191 }
192 }
193 return NULL;
194 }
195
196 /**
197 * We can't include <asn1/asn1.h>, as the ASN1_ definitions would clash
198 * with OpenSSL. Redeclare what we need.
199 */
200 int asn1_known_oid(chunk_t);
201 time_t asn1_to_time(chunk_t *,int);
202
203 /**
204 * Described in header.
205 */
206 int openssl_asn1_known_oid(ASN1_OBJECT *obj)
207 {
208 return asn1_known_oid(openssl_asn1_obj2chunk(obj));
209 }
210
211 /**
212 * Described in header.
213 */
214 time_t openssl_asn1_to_time(ASN1_TIME *time)
215 {
216 chunk_t chunk;
217
218 if (time)
219 {
220 chunk = openssl_asn1_str2chunk(time);
221 switch (time->type)
222 {
223 case V_ASN1_UTCTIME:
224 case V_ASN1_GENERALIZEDTIME:
225 return asn1_to_time(&chunk, time->type);
226 default:
227 break;
228 }
229 }
230 DBG1(DBG_LIB, "invalid ASN1 time");
231 return 0;
232 }