updated openssl plugin to new private/public key API, use encoder framework
[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 /**
105 * Described in header.
106 */
107 bool openssl_bn_split(chunk_t chunk, BIGNUM *a, BIGNUM *b)
108 {
109 int len;
110
111 if ((chunk.len % 2) != 0)
112 {
113 return FALSE;
114 }
115
116 len = chunk.len / 2;
117
118 if (!BN_bin2bn(chunk.ptr, len, a) ||
119 !BN_bin2bn(chunk.ptr + len, len, b))
120 {
121 return FALSE;
122 }
123
124 return TRUE;
125 }
126
127 /**
128 * Build fingerprints of a private/public RSA key.
129 */
130 static bool build_fingerprint(chunk_t key, key_encoding_type_t type, int nid,
131 chunk_t *fingerprint)
132 {
133 hasher_t *hasher;
134
135 hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
136 if (!hasher)
137 {
138 DBG1("SHA1 hash algorithm not supported, fingerprinting failed");
139 return FALSE;
140 }
141 if (type == KEY_ID_PUBKEY_INFO_SHA1)
142 {
143 X509_PUBKEY *pubkey;
144 chunk_t enc;
145 u_char *p;
146
147 /* wrap publicKey in subjectPublicKeyInfo */
148 pubkey = X509_PUBKEY_new();
149 ASN1_OBJECT_free(pubkey->algor->algorithm);
150 pubkey->algor->algorithm = OBJ_nid2obj(nid);
151
152 if (pubkey->algor->parameter == NULL ||
153 pubkey->algor->parameter->type != V_ASN1_NULL)
154 {
155 ASN1_TYPE_free(pubkey->algor->parameter);
156 pubkey->algor->parameter = ASN1_TYPE_new();
157 pubkey->algor->parameter->type = V_ASN1_NULL;
158 }
159 M_ASN1_BIT_STRING_set(pubkey->public_key, enc.ptr, enc.len);
160
161 enc = chunk_alloc(i2d_X509_PUBKEY(pubkey, NULL));
162 p = enc.ptr;
163 i2d_X509_PUBKEY(pubkey, &p);
164 X509_PUBKEY_free(pubkey);
165
166 hasher->allocate_hash(hasher, enc, fingerprint);
167 chunk_free(&enc);
168 }
169 else
170 {
171 hasher->allocate_hash(hasher, key, fingerprint);
172 }
173 hasher->destroy(hasher);
174 return TRUE;
175 }
176
177 /**
178 * See header.
179 */
180 bool openssl_encode(key_encoding_type_t type, chunk_t *encoding, va_list args)
181 {
182 chunk_t key;
183
184 switch (type)
185 {
186 case KEY_PUB_ASN1_DER:
187 if (key_encoding_args(args, KEY_PART_RSA_PUB_ASN1_DER, &key,
188 KEY_PART_END) ||
189 key_encoding_args(args, KEY_PART_ECDSA_PUB_ASN1_DER, &key,
190 KEY_PART_END))
191 {
192 *encoding = chunk_clone(key);
193 return TRUE;
194 }
195 return FALSE;
196 case KEY_PRIV_ASN1_DER:
197 if (key_encoding_args(args, KEY_PART_RSA_PRIV_ASN1_DER, &key,
198 KEY_PART_END) ||
199 key_encoding_args(args, KEY_PART_ECDSA_PRIV_ASN1_DER, &key,
200 KEY_PART_END))
201 {
202 *encoding = chunk_clone(key);
203 return TRUE;
204 }
205 return FALSE;
206 case KEY_ID_PUBKEY_SHA1:
207 case KEY_ID_PUBKEY_INFO_SHA1:
208 if (key_encoding_args(args, KEY_PART_RSA_PUB_ASN1_DER, &key,
209 KEY_PART_END))
210 {
211 return build_fingerprint(key, type, NID_rsaEncryption, encoding);
212 }
213 else if (key_encoding_args(args, KEY_PART_ECDSA_PUB_ASN1_DER, &key,
214 KEY_PART_END))
215 {
216 return build_fingerprint(key, type, NID_X9_62_id_ecPublicKey,
217 encoding);
218 }
219 return FALSE;
220 default:
221 return FALSE;
222 }
223 }
224