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