2 * Copyright (C) 2008 Martin Willi
3 * Hochschule fuer Technik Rapperswil
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 #include "stroke_cred.h"
19 #include "stroke_shared_key.h"
23 #include <credentials/certificates/x509.h>
24 #include <credentials/certificates/crl.h>
25 #include <credentials/certificates/ac.h>
26 #include <utils/linked_list.h>
27 #include <utils/mutex.h>
28 #include <utils/lexparser.h>
29 #include <asn1/ttodata.h>
33 /* configuration directories and files */
34 #define CONFIG_DIR IPSEC_CONFDIR
35 #define IPSEC_D_DIR CONFIG_DIR "/ipsec.d"
36 #define PRIVATE_KEY_DIR IPSEC_D_DIR "/private"
37 #define CERTIFICATE_DIR IPSEC_D_DIR "/certs"
38 #define CA_CERTIFICATE_DIR IPSEC_D_DIR "/cacerts"
39 #define AA_CERTIFICATE_DIR IPSEC_D_DIR "/aacerts"
40 #define ATTR_CERTIFICATE_DIR IPSEC_D_DIR "/acerts"
41 #define OCSP_CERTIFICATE_DIR IPSEC_D_DIR "/ocspcerts"
42 #define CRL_DIR IPSEC_D_DIR "/crls"
43 #define SECRETS_FILE CONFIG_DIR "/ipsec.secrets"
45 typedef struct private_stroke_cred_t private_stroke_cred_t
;
48 * private data of stroke_cred
50 struct private_stroke_cred_t
{
58 * list of trusted peer/signer/CA certificates (certificate_t)
63 * list of shared secrets (private_shared_key_t)
65 linked_list_t
*shared
;
68 * list of private keys (private_key_t)
70 linked_list_t
*private;
73 * mutex to lock lists above
79 * data to pass to various filters
82 private_stroke_cred_t
*this;
87 * destroy id enumerator data and unlock list
89 static void id_data_destroy(id_data_t
*data
)
91 data
->this->mutex
->unlock(data
->this->mutex
);
96 * filter function for private key enumerator
98 static bool private_filter(id_data_t
*data
,
99 private_key_t
**in
, private_key_t
**out
)
101 identification_t
*candidate
;
103 if (data
->id
== NULL
)
108 candidate
= (*in
)->get_id(*in
, data
->id
->get_type(data
->id
));
109 if (candidate
&& data
->id
->equals(data
->id
, candidate
))
118 * Implements credential_set_t.create_private_enumerator
120 static enumerator_t
* create_private_enumerator(private_stroke_cred_t
*this,
121 key_type_t type
, identification_t
*id
)
125 if (type
!= KEY_RSA
&& type
!= KEY_ANY
)
126 { /* we only have RSA keys */
129 data
= malloc_thing(id_data_t
);
133 this->mutex
->lock(this->mutex
);
134 return enumerator_create_filter(this->private->create_enumerator(this->private),
135 (void*)private_filter
, data
,
136 (void*)id_data_destroy
);
140 * filter function for certs enumerator
142 static bool certs_filter(id_data_t
*data
, certificate_t
**in
, certificate_t
**out
)
144 public_key_t
*public;
145 identification_t
*candidate
;
146 certificate_t
*cert
= *in
;
148 if (cert
->get_type(cert
) == CERT_X509_CRL
)
153 if (data
->id
== NULL
|| cert
->has_subject(cert
, data
->id
))
159 public = (cert
)->get_public_key(cert
);
162 candidate
= public->get_id(public, data
->id
->get_type(data
->id
));
163 if (candidate
&& data
->id
->equals(data
->id
, candidate
))
165 public->destroy(public);
169 public->destroy(public);
175 * filter function for crl enumerator
177 static bool crl_filter(id_data_t
*data
, certificate_t
**in
, certificate_t
**out
)
179 certificate_t
*cert
= *in
;
181 if (cert
->get_type(cert
) != CERT_X509_CRL
)
186 if (data
->id
== NULL
|| cert
->has_issuer(cert
, data
->id
))
195 * Implements credential_set_t.create_cert_enumerator
197 static enumerator_t
* create_cert_enumerator(private_stroke_cred_t
*this,
198 certificate_type_t cert
, key_type_t key
,
199 identification_t
*id
, bool trusted
)
203 if (cert
== CERT_X509_CRL
)
210 data
= malloc_thing(id_data_t
);
214 this->mutex
->lock(this->mutex
);
215 return enumerator_create_filter(this->certs
->create_enumerator(this->certs
),
216 (void*)crl_filter
, data
,
217 (void*)id_data_destroy
);
219 if (cert
!= CERT_X509
&& cert
!= CERT_ANY
)
220 { /* we only have X509 certificates. TODO: ACs? */
223 if (key
!= KEY_RSA
&& key
!= KEY_ANY
)
224 { /* we only have RSA keys */
227 data
= malloc_thing(id_data_t
);
231 this->mutex
->lock(this->mutex
);
232 return enumerator_create_filter(this->certs
->create_enumerator(this->certs
),
233 (void*)certs_filter
, data
,
234 (void*)id_data_destroy
);
238 private_stroke_cred_t
*this;
239 identification_t
*me
;
240 identification_t
*other
;
241 shared_key_type_t type
;
245 * free shared key enumerator data and unlock list
247 static void shared_data_destroy(shared_data_t
*data
)
249 data
->this->mutex
->unlock(data
->this->mutex
);
254 * filter function for certs enumerator
256 static bool shared_filter(shared_data_t
*data
,
257 stroke_shared_key_t
**in
, shared_key_t
**out
,
258 void **unused1
, id_match_t
*me
,
259 void **unused2
, id_match_t
*other
)
261 id_match_t my_match
, other_match
;
262 stroke_shared_key_t
*stroke
= *in
;
263 shared_key_t
*shared
= &stroke
->shared
;
265 if (data
->type
!= SHARED_ANY
&& shared
->get_type(shared
) != data
->type
)
270 my_match
= stroke
->has_owner(stroke
, data
->me
);
271 other_match
= stroke
->has_owner(stroke
, data
->other
);
272 if (!my_match
&& !other_match
)
283 *other
= other_match
;
289 * Implements credential_set_t.create_shared_enumerator
291 static enumerator_t
* create_shared_enumerator(private_stroke_cred_t
*this,
292 shared_key_type_t type
, identification_t
*me
,
293 identification_t
*other
)
295 shared_data_t
*data
= malloc_thing(shared_data_t
);
301 this->mutex
->lock(this->mutex
);
302 return enumerator_create_filter(this->shared
->create_enumerator(this->shared
),
303 (void*)shared_filter
, data
,
304 (void*)shared_data_destroy
);
308 * Add a certificate to chain
310 static certificate_t
* add_cert(private_stroke_cred_t
*this, certificate_t
*cert
)
312 certificate_t
*current
;
313 enumerator_t
*enumerator
;
316 this->mutex
->lock(this->mutex
);
317 enumerator
= this->certs
->create_enumerator(this->certs
);
318 while (enumerator
->enumerate(enumerator
, (void**)¤t
))
320 if (current
->equals(current
, cert
))
322 /* cert already in queue */
329 enumerator
->destroy(enumerator
);
333 this->certs
->insert_last(this->certs
, cert
);
335 this->mutex
->unlock(this->mutex
);
340 * Implementation of stroke_cred_t.load_ca.
342 static certificate_t
* load_ca(private_stroke_cred_t
*this, char *filename
)
347 if (*filename
== '/')
349 snprintf(path
, sizeof(path
), "%s", filename
);
353 snprintf(path
, sizeof(path
), "%s/%s", CA_CERTIFICATE_DIR
, filename
);
356 cert
= lib
->creds
->create(lib
->creds
,
357 CRED_CERTIFICATE
, CERT_X509
,
358 BUILD_FROM_FILE
, path
,
359 BUILD_X509_FLAG
, X509_CA
,
363 return (certificate_t
*)add_cert(this, cert
);
369 * Add X.509 CRL to chain
371 static void add_crl(private_stroke_cred_t
*this, crl_t
* crl
)
373 certificate_t
*current
, *cert
= &crl
->certificate
;
374 enumerator_t
*enumerator
;
375 bool new = TRUE
, found
= FALSE
;
377 this->mutex
->lock(this->mutex
);
378 enumerator
= this->certs
->create_enumerator(this->certs
);
379 while (enumerator
->enumerate(enumerator
, (void**)¤t
))
381 if (current
->get_type(current
) == CERT_X509_CRL
)
383 crl_t
*crl_c
= (crl_t
*)current
;
384 identification_t
*authkey
= crl
->get_authKeyIdentifier(crl
);
385 identification_t
*authkey_c
= crl_c
->get_authKeyIdentifier(crl_c
);
387 /* if compare authorityKeyIdentifiers if available */
388 if (authkey
!= NULL
&& authkey_c
!= NULL
&&
389 authkey
->equals(authkey
, authkey_c
))
395 identification_t
*issuer
= cert
->get_issuer(cert
);
396 identification_t
*issuer_c
= current
->get_issuer(current
);
398 /* otherwise compare issuer distinguished names */
399 if (issuer
->equals(issuer
, issuer_c
))
406 new = cert
->is_newer(cert
, current
);
409 this->certs
->remove_at(this->certs
, enumerator
);
419 enumerator
->destroy(enumerator
);
423 this->certs
->insert_last(this->certs
, cert
);
425 this->mutex
->unlock(this->mutex
);
429 * Implementation of stroke_cred_t.load_peer.
431 static certificate_t
* load_peer(private_stroke_cred_t
*this, char *filename
)
436 if (*filename
== '/')
438 snprintf(path
, sizeof(path
), "%s", filename
);
442 snprintf(path
, sizeof(path
), "%s/%s", CERTIFICATE_DIR
, filename
);
445 cert
= lib
->creds
->create(lib
->creds
,
446 CRED_CERTIFICATE
, CERT_X509
,
447 BUILD_FROM_FILE
, path
,
452 cert
= add_cert(this, cert
);
453 return cert
->get_ref(cert
);
459 * load trusted certificates from a directory
461 static void load_certdir(private_stroke_cred_t
*this, char *path
,
462 certificate_type_t type
, x509_flag_t flag
)
467 enumerator_t
*enumerator
= enumerator_create_directory(path
);
471 DBG1(DBG_CFG
, " reading directory failed");
475 while (enumerator
->enumerate(enumerator
, NULL
, &file
, &st
))
479 if (!S_ISREG(st
.st_mode
))
481 /* skip special file */
487 cert
= lib
->creds
->create(lib
->creds
,
488 CRED_CERTIFICATE
, CERT_X509
,
489 BUILD_FROM_FILE
, file
,
490 BUILD_X509_FLAG
, flag
,
494 add_cert(this, cert
);
498 cert
= lib
->creds
->create(lib
->creds
,
499 CRED_CERTIFICATE
, CERT_X509_CRL
,
500 BUILD_FROM_FILE
, file
,
504 add_crl(this, (crl_t
*)cert
);
508 cert
= lib
->creds
->create(lib
->creds
,
509 CRED_CERTIFICATE
, CERT_X509_AC
,
510 BUILD_FROM_FILE
, file
,
521 enumerator
->destroy(enumerator
);
525 * Convert a string of characters into a binary secret
526 * A string between single or double quotes is treated as ASCII characters
527 * A string prepended by 0x is treated as HEX and prepended by 0s as Base64
529 static err_t
extract_secret(chunk_t
*secret
, chunk_t
*line
)
532 char delimiter
= ' ';
535 if (!eat_whitespace(line
))
537 return "missing secret";
540 if (*line
->ptr
== '\'' || *line
->ptr
== '"')
543 delimiter
= *line
->ptr
;
544 line
->ptr
++; line
->len
--;
547 if (!extract_token(&raw_secret
, delimiter
, line
))
549 if (delimiter
== ' ')
555 return "missing second delimiter";
561 /* treat as an ASCII string */
562 *secret
= chunk_clone(raw_secret
);
569 /* secret converted to binary form doesn't use more space than the raw_secret */
570 *secret
= chunk_alloc(raw_secret
.len
);
572 /* convert from HEX or Base64 to binary */
573 ugh
= ttodata(raw_secret
.ptr
, raw_secret
.len
, 0, secret
->ptr
, secret
->len
, &len
);
577 chunk_free_randomized(secret
);
586 * reload ipsec.secrets
588 static void load_secrets(private_stroke_cred_t
*this)
592 chunk_t chunk
, src
, line
;
594 private_key_t
*private;
595 shared_key_t
*shared
;
597 DBG1(DBG_CFG
, "loading secrets from '%s'", SECRETS_FILE
);
599 fd
= fopen(SECRETS_FILE
, "r");
602 DBG1(DBG_CFG
, "opening secrets file '%s' failed");
606 /* TODO: do error checks */
607 fseek(fd
, 0, SEEK_END
);
608 chunk
.len
= ftell(fd
);
610 chunk
.ptr
= malloc(chunk
.len
);
611 bytes
= fread(chunk
.ptr
, 1, chunk
.len
, fd
);
615 this->mutex
->lock(this->mutex
);
616 while (this->shared
->remove_last(this->shared
,
617 (void**)&shared
) == SUCCESS
)
619 shared
->destroy(shared
);
621 while (this->private->remove_last(this->private,
622 (void**)&private) == SUCCESS
)
624 private->destroy(private);
627 while (fetchline(&src
, &line
))
630 shared_key_type_t type
;
634 if (!eat_whitespace(&line
))
638 if (!extract_token(&ids
, ':', &line
))
640 DBG1(DBG_CFG
, "line %d: missing ':' separator", line_nr
);
643 /* NULL terminate the ids string by replacing the : separator */
644 *(ids
.ptr
+ ids
.len
) = '\0';
646 if (!eat_whitespace(&line
) || !extract_token(&token
, ' ', &line
))
648 DBG1(DBG_CFG
, "line %d: missing token", line_nr
);
651 if (match("RSA", &token
))
655 chunk_t secret
= chunk_empty
;
658 chunk_t chunk
= chunk_empty
;
660 err_t ugh
= extract_value(&filename
, &line
);
664 DBG1(DBG_CFG
, "line %d: %s", line_nr
, ugh
);
667 if (filename
.len
== 0)
669 DBG1(DBG_CFG
, "line %d: empty filename", line_nr
);
672 if (*filename
.ptr
== '/')
674 /* absolute path name */
675 snprintf(path
, sizeof(path
), "%.*s", filename
.len
, filename
.ptr
);
679 /* relative path name */
680 snprintf(path
, sizeof(path
), "%s/%.*s", PRIVATE_KEY_DIR
,
681 filename
.len
, filename
.ptr
);
684 /* check for optional passphrase */
685 if (eat_whitespace(&line
))
687 ugh
= extract_secret(&secret
, &line
);
690 DBG1(DBG_CFG
, "line %d: malformed passphrase: %s", line_nr
, ugh
);
695 if (pem_asn1_load_file(path
, &secret
, &chunk
, &pgp
))
697 key
= lib
->creds
->create(lib
->creds
, CRED_PRIVATE_KEY
, KEY_RSA
,
698 BUILD_BLOB_ASN1_DER
, chunk
, BUILD_END
);
701 DBG1(DBG_CFG
, " loaded private key file '%s'", path
);
702 this->private->insert_last(this->private, key
);
705 chunk_free_randomized(&secret
);
707 else if ((match("PSK", &token
) && (type
= SHARED_IKE
)) ||
708 (match("EAP", &token
) && (type
= SHARED_EAP
)) ||
709 (match("XAUTH", &token
) && (type
= SHARED_EAP
)) ||
710 (match("PIN", &token
) && (type
= SHARED_PIN
)))
712 stroke_shared_key_t
*shared_key
;
713 chunk_t secret
= chunk_empty
;
716 err_t ugh
= extract_secret(&secret
, &line
);
719 DBG1(DBG_CFG
, "line %d: malformed secret: %s", line_nr
, ugh
);
722 shared_key
= stroke_shared_key_create(type
, secret
);
723 DBG1(DBG_CFG
, " loaded %N secret for %s", shared_key_type_names
, type
,
724 ids
.len
> 0 ?
(char*)ids
.ptr
: "%any");
725 DBG4(DBG_CFG
, " secret:", secret
);
727 this->shared
->insert_last(this->shared
, shared_key
);
731 identification_t
*peer_id
;
733 ugh
= extract_value(&id
, &ids
);
736 DBG1(DBG_CFG
, "line %d: %s", line_nr
, ugh
);
744 /* NULL terminate the ID string */
745 *(id
.ptr
+ id
.len
) = '\0';
747 peer_id
= identification_create_from_string(id
.ptr
);
750 DBG1(DBG_CFG
, "line %d: malformed ID: %s", line_nr
, id
.ptr
);
753 if (peer_id
->get_type(peer_id
) == ID_ANY
)
755 peer_id
->destroy(peer_id
);
759 shared_key
->add_owner(shared_key
, peer_id
);
764 shared_key
->add_owner(shared_key
,
765 identification_create_from_encoding(ID_ANY
, chunk_empty
));
770 DBG1(DBG_CFG
, "line %d: token must be either "
771 "RSA, PSK, EAP, or PIN", line_nr
);
776 this->mutex
->unlock(this->mutex
);
777 chunk_free_randomized(&chunk
);
781 * load all certificates from ipsec.d
783 static void load_certs(private_stroke_cred_t
*this)
785 DBG1(DBG_CFG
, "loading ca certificates from '%s'",
787 load_certdir(this, CA_CERTIFICATE_DIR
, CERT_X509
, X509_CA
);
789 DBG1(DBG_CFG
, "loading aa certificates from '%s'",
791 load_certdir(this, AA_CERTIFICATE_DIR
, CERT_X509
, X509_AA
);
793 DBG1(DBG_CFG
, "loading ocsp signer certificates from '%s'",
794 OCSP_CERTIFICATE_DIR
);
795 load_certdir(this, OCSP_CERTIFICATE_DIR
, CERT_X509
, X509_OCSP_SIGNER
);
797 DBG1(DBG_CFG
, "loading attribute certificates from '%s'",
798 ATTR_CERTIFICATE_DIR
);
799 load_certdir(this, ATTR_CERTIFICATE_DIR
, CERT_X509_AC
, 0);
801 DBG1(DBG_CFG
, "loading crls from '%s'",
803 load_certdir(this, CRL_DIR
, CERT_X509_CRL
, 0);
807 * Implementation of stroke_cred_t.reread.
809 static void reread(private_stroke_cred_t
*this, stroke_msg_t
*msg
)
811 if (msg
->reread
.flags
& REREAD_SECRETS
)
813 DBG1(DBG_CFG
, "rereading secrets");
816 if (msg
->reread
.flags
& REREAD_CACERTS
)
818 DBG1(DBG_CFG
, "rereading ca certificates from '%s'",
820 load_certdir(this, CA_CERTIFICATE_DIR
, CERT_X509
, X509_CA
);
822 if (msg
->reread
.flags
& REREAD_OCSPCERTS
)
824 DBG1(DBG_CFG
, "rereading ocsp signer certificates from '%s'",
825 OCSP_CERTIFICATE_DIR
);
826 load_certdir(this, OCSP_CERTIFICATE_DIR
, CERT_X509
,
829 if (msg
->reread
.flags
& REREAD_AACERTS
)
831 DBG1(DBG_CFG
, "rereading aa certificates from '%s'",
833 load_certdir(this, AA_CERTIFICATE_DIR
, CERT_X509
, X509_AA
);
835 if (msg
->reread
.flags
& REREAD_ACERTS
)
837 DBG1(DBG_CFG
, "rereading attribute certificates from '%s'",
838 ATTR_CERTIFICATE_DIR
);
839 load_certdir(this, ATTR_CERTIFICATE_DIR
, CERT_X509_AC
, 0);
841 if (msg
->reread
.flags
& REREAD_CRLS
)
843 DBG1(DBG_CFG
, "rereading crls from '%s'",
845 load_certdir(this, CRL_DIR
, CERT_X509_CRL
, 0);
850 * Implementation of stroke_cred_t.destroy
852 static void destroy(private_stroke_cred_t
*this)
854 this->certs
->destroy_offset(this->certs
, offsetof(certificate_t
, destroy
));
855 this->shared
->destroy_offset(this->shared
, offsetof(shared_key_t
, destroy
));
856 this->private->destroy_offset(this->private, offsetof(private_key_t
, destroy
));
857 this->mutex
->destroy(this->mutex
);
864 stroke_cred_t
*stroke_cred_create()
866 private_stroke_cred_t
*this = malloc_thing(private_stroke_cred_t
);
868 this->public.set
.create_private_enumerator
= (void*)create_private_enumerator
;
869 this->public.set
.create_cert_enumerator
= (void*)create_cert_enumerator
;
870 this->public.set
.create_shared_enumerator
= (void*)create_shared_enumerator
;
871 this->public.set
.create_cdp_enumerator
= (void*)return_null
;
872 this->public.reread
= (void(*)(stroke_cred_t
*, stroke_msg_t
*msg
))reread
;
873 this->public.load_ca
= (certificate_t
*(*)(stroke_cred_t
*, char *filename
))load_ca
;
874 this->public.load_peer
= (certificate_t
*(*)(stroke_cred_t
*, char *filename
))load_peer
;
875 this->public.destroy
= (void(*)(stroke_cred_t
*))destroy
;
877 this->certs
= linked_list_create();
878 this->shared
= linked_list_create();
879 this->private = linked_list_create();
880 this->mutex
= mutex_create(MUTEX_RECURSIVE
);
885 return &this->public;