use libstrongswan for private key loading, whack callback to read passphrase
[strongswan.git] / src / pluto / certs.c
1 /* Certificate support for IKE authentication
2 * Copyright (C) 2002-2009 Andreas Steffen
3 *
4 * HSR - 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 <stdlib.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <unistd.h>
21
22 #include <freeswan.h>
23
24 #include "library.h"
25 #include "asn1/asn1.h"
26
27 #include "constants.h"
28 #include "defs.h"
29 #include "log.h"
30 #include "id.h"
31 #include "pem.h"
32 #include "certs.h"
33 #include "whack.h"
34
35 /**
36 * used for initializatin of certs
37 */
38 const cert_t cert_empty = {CERT_NONE, {NULL}};
39
40 /**
41 * extracts the certificate to be sent to the peer
42 */
43 chunk_t cert_get_encoding(cert_t cert)
44 {
45 switch (cert.type)
46 {
47 case CERT_PGP:
48 return cert.u.pgp->certificate;
49 case CERT_X509_SIGNATURE:
50 return cert.u.x509->certificate;
51 default:
52 return chunk_empty;
53 }
54 }
55
56 public_key_t* cert_get_public_key(const cert_t cert)
57 {
58 switch (cert.type)
59 {
60 case CERT_PGP:
61 return cert.u.pgp->public_key;
62 break;
63 case CERT_X509_SIGNATURE:
64 return cert.u.x509->public_key;
65 break;
66 default:
67 return NULL;
68 }
69 }
70
71 /* load a coded key or certificate file with autodetection
72 * of binary DER or base64 PEM ASN.1 formats and armored PGP format
73 */
74 bool load_coded_file(char *filename, prompt_pass_t *pass, const char *type,
75 chunk_t *blob, bool *pgp)
76 {
77 err_t ugh = NULL;
78
79 FILE *fd = fopen(filename, "r");
80
81 if (fd)
82 {
83 int bytes;
84 fseek(fd, 0, SEEK_END );
85 blob->len = ftell(fd);
86 rewind(fd);
87 blob->ptr = malloc(blob->len);
88 bytes = fread(blob->ptr, 1, blob->len, fd);
89 fclose(fd);
90 plog(" loaded %s file '%s' (%d bytes)", type, filename, bytes);
91
92 *pgp = FALSE;
93
94 /* try DER format */
95 if (is_asn1(*blob))
96 {
97 DBG(DBG_PARSING,
98 DBG_log(" file coded in DER format");
99 )
100 return TRUE;
101 }
102
103 /* try PEM format */
104 ugh = pemtobin(blob, pass, filename, pgp);
105
106 if (ugh == NULL)
107 {
108 if (*pgp)
109 {
110 DBG(DBG_PARSING,
111 DBG_log(" file coded in armored PGP format");
112 )
113 return TRUE;
114 }
115 if (is_asn1(*blob))
116 {
117 DBG(DBG_PARSING,
118 DBG_log(" file coded in PEM format");
119 )
120 return TRUE;
121 }
122 ugh = "file coded in unknown format, discarded";
123 }
124
125 /* a conversion error has occured */
126 plog(" %s", ugh);
127 free(blob->ptr);
128 *blob = chunk_empty;
129 }
130 else
131 {
132 plog(" could not open %s file '%s'", type, filename);
133 }
134 return FALSE;
135 }
136
137 /**
138 * Passphrase callback to read from whack fd
139 */
140 chunk_t whack_pass_cb(prompt_pass_t *pass, int try)
141 {
142 int n;
143
144 if (try > MAX_PROMPT_PASS_TRIALS)
145 {
146 whack_log(RC_LOG_SERIOUS, "invalid passphrase, too many trials");
147 return chunk_empty;
148 }
149 if (try == 1)
150 {
151 whack_log(RC_ENTERSECRET, "need passphrase for 'private key'");
152 }
153 else
154 {
155 whack_log(RC_ENTERSECRET, "invalid passphrase, please try again");
156 }
157
158 n = read(pass->fd, pass->secret, PROMPT_PASS_LEN);
159
160 if (n == -1)
161 {
162 whack_log(RC_LOG_SERIOUS, "read(whackfd) failed");
163 return chunk_empty;
164 }
165
166 pass->secret[n-1] = '\0';
167
168 if (strlen(pass->secret) == 0)
169 {
170 whack_log(RC_LOG_SERIOUS, "no passphrase entered, aborted");
171 return chunk_empty;
172 }
173 return chunk_create(pass->secret, strlen(pass->secret));
174 }
175
176 /**
177 * Loads a PKCS#1 or PGP privatekey file
178 */
179 private_key_t* load_private_key(char* filename, prompt_pass_t *pass,
180 key_type_t type)
181 {
182 private_key_t *key = NULL;
183 char *path;
184
185 path = concatenate_paths(PRIVATE_KEY_PATH, filename);
186 if (pass && pass->prompt && pass->fd != NULL_FD)
187 { /* use passphrase callback */
188 key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
189 BUILD_FROM_FILE, path,
190 BUILD_PASSPHRASE_CALLBACK, whack_pass_cb, pass,
191 BUILD_END);
192 if (key)
193 {
194 whack_log(RC_SUCCESS, "valid passphrase");
195 }
196 }
197 else if (pass)
198 { /* use a given passphrase */
199 chunk_t password = chunk_create(pass->secret, strlen(pass->secret));
200 key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
201 BUILD_FROM_FILE, path,
202 BUILD_PASSPHRASE, password, BUILD_END);
203 }
204 else
205 { /* no passphrase */
206 key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
207 BUILD_FROM_FILE, path, BUILD_END);
208
209 }
210 if (key == NULL)
211 {
212 plog(" syntax error in private key file");
213 }
214 return key;
215 }
216
217 /**
218 * Loads a X.509 or OpenPGP certificate
219 */
220 bool load_cert(char *filename, const char *label, cert_t *cert)
221 {
222 bool pgp = FALSE;
223 chunk_t blob = chunk_empty;
224
225 /* initialize cert struct */
226 cert->type = CERT_NONE;
227 cert->u.x509 = NULL;
228
229 if (load_coded_file(filename, NULL, label, &blob, &pgp))
230 {
231 if (pgp)
232 {
233 pgpcert_t *pgpcert = malloc_thing(pgpcert_t);
234 *pgpcert = pgpcert_empty;
235 if (parse_pgp(blob, pgpcert, NULL))
236 {
237 cert->type = CERT_PGP;
238 cert->u.pgp = pgpcert;
239 return TRUE;
240 }
241 else
242 {
243 plog(" error in OpenPGP certificate");
244 free_pgpcert(pgpcert);
245 return FALSE;
246 }
247 }
248 else
249 {
250 x509cert_t *x509cert = malloc_thing(x509cert_t);
251 *x509cert = empty_x509cert;
252 if (parse_x509cert(blob, 0, x509cert))
253 {
254 cert->type = CERT_X509_SIGNATURE;
255 cert->u.x509 = x509cert;
256 return TRUE;
257 }
258 else
259 {
260 plog(" error in X.509 certificate");
261 free_x509cert(x509cert);
262 return FALSE;
263 }
264 }
265 }
266 return FALSE;
267 }
268
269 /**
270 * Loads a host certificate
271 */
272 bool load_host_cert(char *filename, cert_t *cert)
273 {
274 char *path = concatenate_paths(HOST_CERT_PATH, filename);
275
276 return load_cert(path, "host cert", cert);
277 }
278
279 /**
280 * Loads a CA certificate
281 */
282 bool load_ca_cert(char *filename, cert_t *cert)
283 {
284 char *path = concatenate_paths(CA_CERT_PATH, filename);
285
286 return load_cert(path, "CA cert", cert);
287 }
288
289 /**
290 * establish equality of two certificates
291 */
292 bool same_cert(const cert_t *a, const cert_t *b)
293 {
294 return a->type == b->type && a->u.x509 == b->u.x509;
295 }
296
297 /**
298 * for each link pointing to the certificate increase the count by one
299 */
300 void share_cert(cert_t cert)
301 {
302 switch (cert.type)
303 {
304 case CERT_PGP:
305 share_pgpcert(cert.u.pgp);
306 break;
307 case CERT_X509_SIGNATURE:
308 share_x509cert(cert.u.x509);
309 break;
310 default:
311 break;
312 }
313 }
314
315 /* release of a certificate decreases the count by one
316 " the certificate is freed when the counter reaches zero
317 */
318 void
319 release_cert(cert_t cert)
320 {
321 switch (cert.type)
322 {
323 case CERT_PGP:
324 release_pgpcert(cert.u.pgp);
325 break;
326 case CERT_X509_SIGNATURE:
327 release_x509cert(cert.u.x509);
328 break;
329 default:
330 break;
331 }
332 }
333
334 /*
335 * list all X.509 and OpenPGP end certificates
336 */
337 void
338 list_certs(bool utc)
339 {
340 list_x509_end_certs(utc);
341 list_pgp_end_certs(utc);
342 }
343