Use bits instead of bytes for a private/public key
[strongswan.git] / src / pluto / x509.c
1 /* Support of X.509 certificates
2 * Copyright (C) 2000 Andreas Hess, Patric Lichtsteiner, Roger Wegmann
3 * Copyright (C) 2001 Marco Bertossa, Andreas Schleiss
4 * Copyright (C) 2002 Mario Strasser
5 * Copyright (C) 2000-2009 Andreas Steffen - Hochschule fuer Technik Rapperswil
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 */
17
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <unistd.h>
22 #include <dirent.h>
23 #include <time.h>
24 #include <sys/types.h>
25
26 #include <freeswan.h>
27
28 #include <asn1/asn1.h>
29 #include <crypto/hashers/hasher.h>
30 #include <utils/enumerator.h>
31 #include <utils/identification.h>
32
33 #include "constants.h"
34 #include "defs.h"
35 #include "log.h"
36 #include "x509.h"
37 #include "crl.h"
38 #include "ca.h"
39 #include "certs.h"
40 #include "keys.h"
41 #include "whack.h"
42 #include "fetch.h"
43 #include "ocsp.h"
44
45 /**
46 * Check for equality between two key identifiers
47 */
48 bool same_keyid(chunk_t a, chunk_t b)
49 {
50 if (a.ptr == NULL || b.ptr == NULL)
51 {
52 return FALSE;
53 }
54 return chunk_equals(a, b);
55 }
56
57 /**
58 * Stores a chained list of end certs and CA certs
59 */
60 void store_x509certs(linked_list_t *certs, bool strict)
61 {
62 cert_t *x509cert, *cacerts = NULL;
63 certificate_t *cert;
64 enumerator_t *enumerator;
65
66 /* first extract CA certs, ignoring self-signed root CA certs */
67
68 enumerator = certs->create_enumerator(certs);
69 while (enumerator->enumerate(enumerator, &cert))
70 {
71 x509_t *x509 = (x509_t*)cert;
72 x509_flag_t flags;
73
74 flags = x509->get_flags(x509);
75 if (flags & X509_CA)
76 {
77 /* we don't accept self-signed CA certs */
78 if (flags & X509_SELF_SIGNED)
79 {
80 plog("self-signed cacert rejected");
81 }
82 else
83 {
84 /* insertion into temporary chain of candidate CA certs */
85 x509cert = malloc_thing(cert_t);
86 *x509cert = cert_empty;
87 x509cert->cert = cert->get_ref(cert);
88 x509cert->next = cacerts;
89 cacerts = x509cert;
90 }
91 }
92 }
93 enumerator->destroy(enumerator);
94
95 /* now verify the candidate CA certs */
96
97 while (cacerts)
98 {
99 cert_t *cert = cacerts;
100
101 cacerts = cacerts->next;
102
103 if (trust_authcert_candidate(cert, cacerts))
104 {
105 add_authcert(cert, X509_CA);
106 }
107 else
108 {
109 plog("intermediate cacert rejected");
110 cert_free(cert);
111 }
112 }
113
114 /* now verify the end certificates */
115
116 enumerator = certs->create_enumerator(certs);
117 while (enumerator->enumerate(enumerator, &cert))
118 {
119 time_t valid_until;
120 x509_t *x509 = (x509_t*)cert;
121
122 if (!(x509->get_flags(x509) & X509_CA))
123 {
124 x509cert = malloc_thing(cert_t);
125 *x509cert = cert_empty;
126 x509cert->cert = cert->get_ref(cert);
127
128 if (verify_x509cert(x509cert, strict, &valid_until))
129 {
130 DBG(DBG_CONTROL | DBG_PARSING,
131 DBG_log("public key validated")
132 )
133 add_public_key_from_cert(x509cert, valid_until, DAL_SIGNED);
134 }
135 else
136 {
137 plog("X.509 certificate rejected");
138 cert_free(x509cert);
139 }
140 }
141 }
142 enumerator->destroy(enumerator);
143 }
144
145 /**
146 * Check if a signature over binary blob is genuine
147 */
148 bool x509_check_signature(chunk_t tbs, chunk_t sig, int algorithm,
149 certificate_t *issuer_cert)
150 {
151 bool success;
152 public_key_t *key;
153 signature_scheme_t scheme;
154
155 scheme = signature_scheme_from_oid(algorithm);
156 if (scheme == SIGN_UNKNOWN)
157 {
158 return FALSE;
159 }
160
161 key = issuer_cert->get_public_key(issuer_cert);
162 if (key == NULL)
163 {
164 return FALSE;
165 }
166 success = key->verify(key, scheme, tbs, sig);
167 key->destroy(key);
168
169 return success;
170 }
171
172 /**
173 * Build an ASN.1 encoded PKCS#1 signature over a binary blob
174 */
175 chunk_t x509_build_signature(chunk_t tbs, int algorithm, private_key_t *key,
176 bool bit_string)
177 {
178 chunk_t signature;
179 signature_scheme_t scheme = signature_scheme_from_oid(algorithm);
180
181 if (scheme == SIGN_UNKNOWN || !key->sign(key, scheme, tbs, &signature))
182 {
183 return chunk_empty;
184 }
185 return (bit_string) ? asn1_bitstring("m", signature)
186 : asn1_wrap(ASN1_OCTET_STRING, "m", signature);
187 }
188
189 /**
190 * Verifies a X.509 certificate
191 */
192 bool verify_x509cert(cert_t *cert, bool strict, time_t *until)
193 {
194 int pathlen, pathlen_constraint;
195
196 *until = 0;
197
198 for (pathlen = -1; pathlen <= X509_MAX_PATH_LEN; pathlen++)
199 {
200 certificate_t *certificate = cert->cert;
201 identification_t *subject = certificate->get_subject(certificate);
202 identification_t *issuer = certificate->get_issuer(certificate);
203 x509_t *x509 = (x509_t*)certificate;
204 chunk_t authKeyID = x509->get_authKeyIdentifier(x509);
205 cert_t *issuer_cert;
206 time_t notBefore, notAfter;
207 bool valid;
208
209 DBG(DBG_CONTROL,
210 DBG_log("subject: '%Y'", subject);
211 DBG_log("issuer: '%Y'", issuer);
212 if (authKeyID.ptr)
213 {
214 DBG_log("authkey: %#B", &authKeyID);
215 }
216 )
217
218 valid = certificate->get_validity(certificate, NULL,
219 &notBefore, &notAfter);
220 if (*until == UNDEFINED_TIME || notAfter < *until)
221 {
222 *until = notAfter;
223 }
224 if (!valid)
225 {
226 plog("certificate is invalid (valid from %T to %T)",
227 &notBefore, FALSE, &notAfter, FALSE);
228 return FALSE;
229 }
230 DBG(DBG_CONTROL,
231 DBG_log("certificate is valid")
232 )
233
234 lock_authcert_list("verify_x509cert");
235 issuer_cert = get_authcert(issuer, authKeyID, X509_CA);
236 if (issuer_cert == NULL)
237 {
238 plog("issuer cacert not found");
239 unlock_authcert_list("verify_x509cert");
240 return FALSE;
241 }
242 DBG(DBG_CONTROL,
243 DBG_log("issuer cacert found")
244 )
245
246 if (!certificate->issued_by(certificate, issuer_cert->cert))
247 {
248 plog("certificate signature is invalid");
249 unlock_authcert_list("verify_x509cert");
250 return FALSE;
251 }
252 DBG(DBG_CONTROL,
253 DBG_log("certificate signature is valid")
254 )
255 unlock_authcert_list("verify_x509cert");
256
257 /* check path length constraint */
258 pathlen_constraint = x509->get_pathLenConstraint(x509);
259 if (pathlen_constraint != X509_NO_PATH_LEN_CONSTRAINT &&
260 pathlen > pathlen_constraint)
261 {
262 plog("path length of %d violates constraint of %d",
263 pathlen, pathlen_constraint);
264 return FALSE;
265 }
266
267 /* check if cert is a self-signed root ca */
268 if (pathlen >= 0 && (x509->get_flags(x509) & X509_SELF_SIGNED))
269 {
270 DBG(DBG_CONTROL,
271 DBG_log("reached self-signed root ca with a path length of %d",
272 pathlen)
273 )
274 return TRUE;
275 }
276 else
277 {
278 time_t nextUpdate = *until;
279 time_t revocationDate = UNDEFINED_TIME;
280 crl_reason_t revocationReason = CRL_REASON_UNSPECIFIED;
281
282 /* first check certificate revocation using ocsp */
283 cert_status_t status = verify_by_ocsp(cert, &nextUpdate
284 , &revocationDate, &revocationReason);
285
286 /* if ocsp service is not available then fall back to crl */
287 if ((status == CERT_UNDEFINED)
288 || (status == CERT_UNKNOWN && strict))
289 {
290 status = verify_by_crl(cert, &nextUpdate, &revocationDate
291 , &revocationReason);
292 }
293
294 switch (status)
295 {
296 case CERT_GOOD:
297 /* if status information is stale */
298 if (strict && nextUpdate < time(NULL))
299 {
300 DBG(DBG_CONTROL,
301 DBG_log("certificate is good but status is stale")
302 )
303 remove_x509_public_key(cert);
304 return FALSE;
305 }
306 DBG(DBG_CONTROL,
307 DBG_log("certificate is good")
308 )
309
310 /* with strict crl policy the public key must have the same
311 * lifetime as the validity of the ocsp status or crl lifetime
312 */
313 if (strict && nextUpdate < *until)
314 {
315 *until = nextUpdate;
316 }
317 break;
318 case CERT_REVOKED:
319 plog("certificate was revoked on %T, reason: %N"
320 , &revocationDate, TRUE
321 , crl_reason_names, revocationReason);
322 remove_x509_public_key(cert);
323 return FALSE;
324 case CERT_UNKNOWN:
325 case CERT_UNDEFINED:
326 default:
327 plog("certificate status unknown");
328 if (strict)
329 {
330 remove_x509_public_key(cert);
331 return FALSE;
332 }
333 break;
334 }
335 }
336
337 /* go up one step in the trust chain */
338 cert = issuer_cert;
339 }
340 plog("maximum path length of %d exceeded", X509_MAX_PATH_LEN);
341 return FALSE;
342 }
343
344 /**
345 * List all X.509 certs in a chained list
346 */
347 void list_x509cert_chain(const char *caption, cert_t* cert,
348 x509_flag_t flags, bool utc)
349 {
350 bool first = TRUE;
351 time_t now;
352
353 /* determine the current time */
354 time(&now);
355
356 while (cert)
357 {
358 certificate_t *certificate = cert->cert;
359 x509_t *x509 = (x509_t*)certificate;
360
361 if (certificate->get_type(certificate) == CERT_X509 &&
362 (flags == X509_NONE || (flags & x509->get_flags(x509))))
363 {
364 enumerator_t *enumerator;
365 char buf[BUF_LEN];
366 char *pos = buf;
367 int len = BUF_LEN, pathlen;
368 bool first_altName = TRUE;
369 identification_t *id;
370 time_t notBefore, notAfter;
371 public_key_t *key;
372 chunk_t serial, keyid, subjkey, authkey;
373
374 if (first)
375 {
376 whack_log(RC_COMMENT, " ");
377 whack_log(RC_COMMENT, "List of X.509 %s Certificates:", caption);
378 first = FALSE;
379 }
380 whack_log(RC_COMMENT, " ");
381
382 enumerator = x509->create_subjectAltName_enumerator(x509);
383 while (enumerator->enumerate(enumerator, &id))
384 {
385 int written;
386
387 if (first_altName)
388 {
389 written = snprintf(pos, len, "%Y", id);
390 first_altName = FALSE;
391 }
392 else
393 {
394 written = snprintf(pos, len, ", %Y", id);
395 }
396 if (written < 0 || written >= len)
397 {
398 break;
399 }
400 pos += written;
401 len -= written;
402 }
403 enumerator->destroy(enumerator);
404 if (!first_altName)
405 {
406 whack_log(RC_COMMENT, " altNames: %s", buf);
407 }
408
409 whack_log(RC_COMMENT, " subject: \"%Y\"",
410 certificate->get_subject(certificate));
411 whack_log(RC_COMMENT, " issuer: \"%Y\"",
412 certificate->get_issuer(certificate));
413 serial = x509->get_serial(x509);
414 whack_log(RC_COMMENT, " serial: %#B", &serial);
415
416 /* list validity */
417 certificate->get_validity(certificate, &now, &notBefore, &notAfter);
418 whack_log(RC_COMMENT, " validity: not before %T %s",
419 &notBefore, utc,
420 (notBefore < now)?"ok":"fatal (not valid yet)");
421 whack_log(RC_COMMENT, " not after %T %s",
422 &notAfter, utc,
423 check_expiry(notAfter, CA_CERT_WARNING_INTERVAL, TRUE));
424
425 key = certificate->get_public_key(certificate);
426 if (key)
427 {
428 whack_log(RC_COMMENT, " pubkey: %N %4d bits%s",
429 key_type_names, key->get_type(key),
430 key->get_keysize(key),
431 cert->smartcard ? ", on smartcard" :
432 (has_private_key(cert)? ", has private key" : ""));
433
434 if (key->get_fingerprint(key, KEYID_PUBKEY_INFO_SHA1, &keyid))
435 {
436 whack_log(RC_COMMENT, " keyid: %#B", &keyid);
437 }
438 if (key->get_fingerprint(key, KEYID_PUBKEY_SHA1, &subjkey))
439 {
440 whack_log(RC_COMMENT, " subjkey: %#B", &subjkey);
441 }
442 key->destroy(key);
443 }
444
445 /* list optional authorityKeyIdentifier */
446 authkey = x509->get_authKeyIdentifier(x509);
447 if (authkey.ptr)
448 {
449 whack_log(RC_COMMENT, " authkey: %#B", &authkey);
450 }
451
452 /* list optional pathLenConstraint */
453 pathlen = x509->get_pathLenConstraint(x509);
454 if (pathlen != X509_NO_PATH_LEN_CONSTRAINT)
455 {
456 whack_log(RC_COMMENT, " pathlen: %d", pathlen);
457 }
458
459 }
460 cert = cert->next;
461 }
462 }
463