use a pluto specific credential builder to build pluto cert_t's
[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 * currently building cert_t
219 */
220 static cert_t *cert_builder_cert;
221
222 /**
223 * builder add function
224 */
225 static void add(builder_t *this, builder_part_t part, ...)
226 {
227 chunk_t blob;
228 va_list args;
229
230 va_start(args, part);
231 blob = va_arg(args, chunk_t);
232 va_end(args);
233
234 switch (part)
235 {
236 case BUILD_BLOB_PGP:
237 {
238 pgpcert_t *pgpcert = malloc_thing(pgpcert_t);
239 *pgpcert = pgpcert_empty;
240 if (parse_pgp(blob, pgpcert))
241 {
242 cert_builder_cert->type = CERT_PGP;
243 cert_builder_cert->u.pgp = pgpcert;
244 }
245 else
246 {
247 plog(" error in OpenPGP certificate");
248 free_pgpcert(pgpcert);
249 }
250 break;
251 }
252 case BUILD_BLOB_ASN1_DER:
253 {
254 x509cert_t *x509cert = malloc_thing(x509cert_t);
255 *x509cert = empty_x509cert;
256 if (parse_x509cert(blob, 0, x509cert))
257 {
258 cert_builder_cert->type = CERT_X509_SIGNATURE;
259 cert_builder_cert->u.x509 = x509cert;
260 }
261 else
262 {
263 plog(" error in X.509 certificate");
264 free_x509cert(x509cert);
265 }
266 break;
267 }
268 default:
269 builder_cancel(this);
270 break;
271 }
272 }
273
274 /**
275 * builder build function
276 */
277 static void *build(builder_t *this)
278 {
279 free(this);
280 if (cert_builder_cert->type == CERT_NONE)
281 {
282 return NULL;
283 }
284 return cert_builder_cert;
285 }
286
287 /**
288 * certificate builder in cert_t format.
289 */
290 static builder_t *cert_builder(credential_type_t type, int subtype)
291 {
292 builder_t *this;
293
294 if (subtype != 1)
295 {
296 return NULL;
297 }
298 this = malloc_thing(builder_t);
299 this->add = add;
300 this->build = build;
301
302 return this;
303 }
304
305 /**
306 * Loads a X.509 or OpenPGP certificate
307 */
308 bool load_cert(char *filename, const char *label, cert_t *cert)
309 {
310 cert_builder_cert = cert;
311
312 cert->type = CERT_NONE;
313 cert->u.x509 = NULL;
314 cert->u.pgp = NULL;
315
316 /* hook in builder functions to build pluto specific certificate format */
317 lib->creds->add_builder(lib->creds, CRED_PLUTO_CERT, 1,
318 (builder_constructor_t)cert_builder);
319 cert = lib->creds->create(lib->creds, CRED_PLUTO_CERT, 1,
320 BUILD_FROM_FILE, filename, BUILD_END);
321 lib->creds->remove_builder(lib->creds,
322 (builder_constructor_t)cert_builder);
323 if (cert)
324 {
325 return TRUE;
326 }
327 return FALSE;
328 }
329
330 /**
331 * Loads a host certificate
332 */
333 bool load_host_cert(char *filename, cert_t *cert)
334 {
335 char *path = concatenate_paths(HOST_CERT_PATH, filename);
336
337 return load_cert(path, "host cert", cert);
338 }
339
340 /**
341 * Loads a CA certificate
342 */
343 bool load_ca_cert(char *filename, cert_t *cert)
344 {
345 char *path = concatenate_paths(CA_CERT_PATH, filename);
346
347 return load_cert(path, "CA cert", cert);
348 }
349
350 /**
351 * establish equality of two certificates
352 */
353 bool same_cert(const cert_t *a, const cert_t *b)
354 {
355 return a->type == b->type && a->u.x509 == b->u.x509;
356 }
357
358 /**
359 * for each link pointing to the certificate increase the count by one
360 */
361 void share_cert(cert_t cert)
362 {
363 switch (cert.type)
364 {
365 case CERT_PGP:
366 share_pgpcert(cert.u.pgp);
367 break;
368 case CERT_X509_SIGNATURE:
369 share_x509cert(cert.u.x509);
370 break;
371 default:
372 break;
373 }
374 }
375
376 /* release of a certificate decreases the count by one
377 " the certificate is freed when the counter reaches zero
378 */
379 void
380 release_cert(cert_t cert)
381 {
382 switch (cert.type)
383 {
384 case CERT_PGP:
385 release_pgpcert(cert.u.pgp);
386 break;
387 case CERT_X509_SIGNATURE:
388 release_x509cert(cert.u.x509);
389 break;
390 default:
391 break;
392 }
393 }
394
395 /*
396 * list all X.509 and OpenPGP end certificates
397 */
398 void
399 list_certs(bool utc)
400 {
401 list_x509_end_certs(utc);
402 list_pgp_end_certs(utc);
403 }
404