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 bool 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
);
430 * Implementation of stroke_cred_t.load_peer.
432 static certificate_t
* load_peer(private_stroke_cred_t
*this, char *filename
)
437 if (*filename
== '/')
439 snprintf(path
, sizeof(path
), "%s", filename
);
443 snprintf(path
, sizeof(path
), "%s/%s", CERTIFICATE_DIR
, filename
);
446 cert
= lib
->creds
->create(lib
->creds
,
447 CRED_CERTIFICATE
, CERT_X509
,
448 BUILD_FROM_FILE
, path
,
453 cert
= add_cert(this, cert
);
454 return cert
->get_ref(cert
);
460 * load trusted certificates from a directory
462 static void load_certdir(private_stroke_cred_t
*this, char *path
,
463 certificate_type_t type
, x509_flag_t flag
)
468 enumerator_t
*enumerator
= enumerator_create_directory(path
);
472 DBG1(DBG_CFG
, " reading directory failed");
476 while (enumerator
->enumerate(enumerator
, NULL
, &file
, &st
))
480 if (!S_ISREG(st
.st_mode
))
482 /* skip special file */
488 cert
= lib
->creds
->create(lib
->creds
,
489 CRED_CERTIFICATE
, CERT_X509
,
490 BUILD_FROM_FILE
, file
,
491 BUILD_X509_FLAG
, flag
,
495 add_cert(this, cert
);
499 cert
= lib
->creds
->create(lib
->creds
,
500 CRED_CERTIFICATE
, CERT_X509_CRL
,
501 BUILD_FROM_FILE
, file
,
505 add_crl(this, (crl_t
*)cert
);
509 cert
= lib
->creds
->create(lib
->creds
,
510 CRED_CERTIFICATE
, CERT_X509_AC
,
511 BUILD_FROM_FILE
, file
,
522 enumerator
->destroy(enumerator
);
526 * Implementation of credential_set_t.cache_cert.
528 static void cache_cert(private_stroke_cred_t
*this, certificate_t
*cert
)
530 if (cert
->get_type(cert
) == CERT_X509_CRL
)
532 /* CRLs get cached to /etc/ipsec.d/crls/authkeyId.der */
533 crl_t
*crl
= (crl_t
*)cert
;
536 if (add_crl(this, crl
))
541 identification_t
*id
;
543 id
= crl
->get_authKeyIdentifier(crl
);
544 chunk
= id
->get_encoding(id
);
545 hex
= chunk_to_hex(chunk
, FALSE
);
546 snprintf(buf
, sizeof(buf
), "%s/%s.der", CRL_DIR
, hex
);
549 chunk
= cert
->get_encoding(cert
);
550 if (chunk_write(chunk
, buf
, 022, TRUE
))
552 DBG1(DBG_CFG
, "cached crl to %s", buf
);
556 DBG1(DBG_CFG
, "caching crl to %s failed", buf
);
564 * Convert a string of characters into a binary secret
565 * A string between single or double quotes is treated as ASCII characters
566 * A string prepended by 0x is treated as HEX and prepended by 0s as Base64
568 static err_t
extract_secret(chunk_t
*secret
, chunk_t
*line
)
571 char delimiter
= ' ';
574 if (!eat_whitespace(line
))
576 return "missing secret";
579 if (*line
->ptr
== '\'' || *line
->ptr
== '"')
582 delimiter
= *line
->ptr
;
583 line
->ptr
++; line
->len
--;
586 if (!extract_token(&raw_secret
, delimiter
, line
))
588 if (delimiter
== ' ')
594 return "missing second delimiter";
600 /* treat as an ASCII string */
601 *secret
= chunk_clone(raw_secret
);
608 /* secret converted to binary form doesn't use more space than the raw_secret */
609 *secret
= chunk_alloc(raw_secret
.len
);
611 /* convert from HEX or Base64 to binary */
612 ugh
= ttodata(raw_secret
.ptr
, raw_secret
.len
, 0, secret
->ptr
, secret
->len
, &len
);
625 * reload ipsec.secrets
627 static void load_secrets(private_stroke_cred_t
*this)
631 chunk_t chunk
, src
, line
;
633 private_key_t
*private;
634 shared_key_t
*shared
;
636 DBG1(DBG_CFG
, "loading secrets from '%s'", SECRETS_FILE
);
638 fd
= fopen(SECRETS_FILE
, "r");
641 DBG1(DBG_CFG
, "opening secrets file '%s' failed");
645 /* TODO: do error checks */
646 fseek(fd
, 0, SEEK_END
);
647 chunk
.len
= ftell(fd
);
649 chunk
.ptr
= malloc(chunk
.len
);
650 bytes
= fread(chunk
.ptr
, 1, chunk
.len
, fd
);
654 this->mutex
->lock(this->mutex
);
655 while (this->shared
->remove_last(this->shared
,
656 (void**)&shared
) == SUCCESS
)
658 shared
->destroy(shared
);
660 while (this->private->remove_last(this->private,
661 (void**)&private) == SUCCESS
)
663 private->destroy(private);
666 while (fetchline(&src
, &line
))
669 shared_key_type_t type
;
673 if (!eat_whitespace(&line
))
677 if (!extract_last_token(&ids
, ':', &line
))
679 DBG1(DBG_CFG
, "line %d: missing ':' separator", line_nr
);
682 /* NULL terminate the ids string by replacing the : separator */
683 *(ids
.ptr
+ ids
.len
) = '\0';
685 if (!eat_whitespace(&line
) || !extract_token(&token
, ' ', &line
))
687 DBG1(DBG_CFG
, "line %d: missing token", line_nr
);
690 if (match("RSA", &token
))
694 chunk_t secret
= chunk_empty
;
697 chunk_t chunk
= chunk_empty
;
699 err_t ugh
= extract_value(&filename
, &line
);
703 DBG1(DBG_CFG
, "line %d: %s", line_nr
, ugh
);
706 if (filename
.len
== 0)
708 DBG1(DBG_CFG
, "line %d: empty filename", line_nr
);
711 if (*filename
.ptr
== '/')
713 /* absolute path name */
714 snprintf(path
, sizeof(path
), "%.*s", filename
.len
, filename
.ptr
);
718 /* relative path name */
719 snprintf(path
, sizeof(path
), "%s/%.*s", PRIVATE_KEY_DIR
,
720 filename
.len
, filename
.ptr
);
723 /* check for optional passphrase */
724 if (eat_whitespace(&line
))
726 ugh
= extract_secret(&secret
, &line
);
729 DBG1(DBG_CFG
, "line %d: malformed passphrase: %s", line_nr
, ugh
);
734 if (pem_asn1_load_file(path
, &secret
, &chunk
, &pgp
))
736 key
= lib
->creds
->create(lib
->creds
, CRED_PRIVATE_KEY
, KEY_RSA
,
737 BUILD_BLOB_ASN1_DER
, chunk
, BUILD_END
);
740 DBG1(DBG_CFG
, " loaded private key file '%s'", path
);
741 this->private->insert_last(this->private, key
);
744 chunk_clear(&secret
);
746 else if ((match("PSK", &token
) && (type
= SHARED_IKE
)) ||
747 (match("EAP", &token
) && (type
= SHARED_EAP
)) ||
748 (match("XAUTH", &token
) && (type
= SHARED_EAP
)) ||
749 (match("PIN", &token
) && (type
= SHARED_PIN
)))
751 stroke_shared_key_t
*shared_key
;
752 chunk_t secret
= chunk_empty
;
755 err_t ugh
= extract_secret(&secret
, &line
);
758 DBG1(DBG_CFG
, "line %d: malformed secret: %s", line_nr
, ugh
);
761 shared_key
= stroke_shared_key_create(type
, secret
);
762 DBG1(DBG_CFG
, " loaded %N secret for %s", shared_key_type_names
, type
,
763 ids
.len
> 0 ?
(char*)ids
.ptr
: "%any");
764 DBG4(DBG_CFG
, " secret: %#B", &secret
);
766 this->shared
->insert_last(this->shared
, shared_key
);
770 identification_t
*peer_id
;
772 ugh
= extract_value(&id
, &ids
);
775 DBG1(DBG_CFG
, "line %d: %s", line_nr
, ugh
);
783 /* NULL terminate the ID string */
784 *(id
.ptr
+ id
.len
) = '\0';
786 peer_id
= identification_create_from_string(id
.ptr
);
789 DBG1(DBG_CFG
, "line %d: malformed ID: %s", line_nr
, id
.ptr
);
792 if (peer_id
->get_type(peer_id
) == ID_ANY
)
794 peer_id
->destroy(peer_id
);
798 shared_key
->add_owner(shared_key
, peer_id
);
803 shared_key
->add_owner(shared_key
,
804 identification_create_from_encoding(ID_ANY
, chunk_empty
));
809 DBG1(DBG_CFG
, "line %d: token must be either "
810 "RSA, PSK, EAP, or PIN", line_nr
);
815 this->mutex
->unlock(this->mutex
);
820 * load all certificates from ipsec.d
822 static void load_certs(private_stroke_cred_t
*this)
824 DBG1(DBG_CFG
, "loading ca certificates from '%s'",
826 load_certdir(this, CA_CERTIFICATE_DIR
, CERT_X509
, X509_CA
);
828 DBG1(DBG_CFG
, "loading aa certificates from '%s'",
830 load_certdir(this, AA_CERTIFICATE_DIR
, CERT_X509
, X509_AA
);
832 DBG1(DBG_CFG
, "loading ocsp signer certificates from '%s'",
833 OCSP_CERTIFICATE_DIR
);
834 load_certdir(this, OCSP_CERTIFICATE_DIR
, CERT_X509
, X509_OCSP_SIGNER
);
836 DBG1(DBG_CFG
, "loading attribute certificates from '%s'",
837 ATTR_CERTIFICATE_DIR
);
838 load_certdir(this, ATTR_CERTIFICATE_DIR
, CERT_X509_AC
, 0);
840 DBG1(DBG_CFG
, "loading crls from '%s'",
842 load_certdir(this, CRL_DIR
, CERT_X509_CRL
, 0);
846 * Implementation of stroke_cred_t.reread.
848 static void reread(private_stroke_cred_t
*this, stroke_msg_t
*msg
)
850 if (msg
->reread
.flags
& REREAD_SECRETS
)
852 DBG1(DBG_CFG
, "rereading secrets");
855 if (msg
->reread
.flags
& REREAD_CACERTS
)
857 DBG1(DBG_CFG
, "rereading ca certificates from '%s'",
859 load_certdir(this, CA_CERTIFICATE_DIR
, CERT_X509
, X509_CA
);
861 if (msg
->reread
.flags
& REREAD_OCSPCERTS
)
863 DBG1(DBG_CFG
, "rereading ocsp signer certificates from '%s'",
864 OCSP_CERTIFICATE_DIR
);
865 load_certdir(this, OCSP_CERTIFICATE_DIR
, CERT_X509
,
868 if (msg
->reread
.flags
& REREAD_AACERTS
)
870 DBG1(DBG_CFG
, "rereading aa certificates from '%s'",
872 load_certdir(this, AA_CERTIFICATE_DIR
, CERT_X509
, X509_AA
);
874 if (msg
->reread
.flags
& REREAD_ACERTS
)
876 DBG1(DBG_CFG
, "rereading attribute certificates from '%s'",
877 ATTR_CERTIFICATE_DIR
);
878 load_certdir(this, ATTR_CERTIFICATE_DIR
, CERT_X509_AC
, 0);
880 if (msg
->reread
.flags
& REREAD_CRLS
)
882 DBG1(DBG_CFG
, "rereading crls from '%s'",
884 load_certdir(this, CRL_DIR
, CERT_X509_CRL
, 0);
889 * Implementation of stroke_cred_t.destroy
891 static void destroy(private_stroke_cred_t
*this)
893 this->certs
->destroy_offset(this->certs
, offsetof(certificate_t
, destroy
));
894 this->shared
->destroy_offset(this->shared
, offsetof(shared_key_t
, destroy
));
895 this->private->destroy_offset(this->private, offsetof(private_key_t
, destroy
));
896 this->mutex
->destroy(this->mutex
);
903 stroke_cred_t
*stroke_cred_create()
905 private_stroke_cred_t
*this = malloc_thing(private_stroke_cred_t
);
907 this->public.set
.create_private_enumerator
= (void*)create_private_enumerator
;
908 this->public.set
.create_cert_enumerator
= (void*)create_cert_enumerator
;
909 this->public.set
.create_shared_enumerator
= (void*)create_shared_enumerator
;
910 this->public.set
.create_cdp_enumerator
= (void*)return_null
;
911 this->public.set
.cache_cert
= (void*)cache_cert
;
912 this->public.reread
= (void(*)(stroke_cred_t
*, stroke_msg_t
*msg
))reread
;
913 this->public.load_ca
= (certificate_t
*(*)(stroke_cred_t
*, char *filename
))load_ca
;
914 this->public.load_peer
= (certificate_t
*(*)(stroke_cred_t
*, char *filename
))load_peer
;
915 this->public.destroy
= (void(*)(stroke_cred_t
*))destroy
;
917 this->certs
= linked_list_create();
918 this->shared
= linked_list_create();
919 this->private = linked_list_create();
920 this->mutex
= mutex_create(MUTEX_RECURSIVE
);
925 return &this->public;