-
Notifications
You must be signed in to change notification settings - Fork 423
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
coap_openssl tidy up, fix first PSK fails if both PSK and PKI are enabled on server #179
Conversation
Remove restriction on requiring PSK / PKI to be set up for a client and using coaps://. This allows the client to talk to a server that is PKI enabled. See Issue #174 |
Updated to set SSL functions at the SSL level, not the CTX level when libcoap is invoked by a client |
7d87ace
to
64e13bc
Compare
Updated in line with the mail thread https://sourceforge.net/p/libcoap/mailman/message/36322888/ |
I still need to add in a callback for server side SNI handling. |
rebased on develop Application CN and SNI callback support provided. libcoap can now the following checking within libcoap /* Options to enable different TLS functionality in libcoap / |
I will do the rebase and update coap-server to be more capable of being more rigorous in the Cert checking shortly. |
rebased and added in -C cafile and -R root_cafile options to both client and server. If -C is defined, then there is verification of certificates. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here is my first round of (minor) comments. I have not yet tested the new PKI-functionality but otherwise, the code looks good (at least as good as code that deals with ASN.1 and X.509 can look ;-)
include/coap/coap_dtls.h
Outdated
* @param asn1_public_cert The ASN.1 encoded (DER) X.509 certificate | ||
* @param asn1_length The ASN.1 length | ||
* @param session The coap session associated with the certificate update | ||
* @param depth Depth in cert chain. If 0, then client cert, else a CA |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could this possibly be negative? Otherwise, I would go for an unsigned type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
depth is derived from X509_STORE_CTX_get_error_depth() which returns an int, so I would prefer this not to be changed, even though the documentation currently states
X509_STORE_CTX_get_error_depth() returns a non-negative error depth
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, the API in coap_dtls.h
is agnostic of the TLS library, therefore I do not think that sticking to OpenSSL idiosyncrasies is preferable to cleaning up the API where possible. You would need to repeat the OpenSSL comment here and in the following explain to people repeatedly why this will never be a negative value...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated to be unsigned as depth should be 0 or greater.
include/coap/coap_dtls.h
Outdated
* Common Name (CN) component of the subject name | ||
* | ||
* @param cn The determined CN from the certificate | ||
* @param asn1_public_cert The ASN.1 encoded (DER) X.509 certificate |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are various parameter names, type names, enum values and struct fields that have "asn1" in their name. To me, it is unclear which internal representation is used for ASN.1. Are these components always serialized as DER, or....? Does this need to be reflected in their identifiers?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OpenSSL is handling the ASN.1 as DER encoding as far as I can tell.
@obgm I can make this asn1der_ prefix if you want.
include/coap/coap_dtls.h
Outdated
const uint8_t *ca_cert; /**< ASN1 Common CA Cert */ | ||
const uint8_t *public_cert; /**< ASN1 Public Cert */ | ||
const uint8_t *private_key; /**< ASN1 Private Key */ | ||
int ca_cert_len; /**< ASN1 CA Cert length */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These three lengths should be size_t
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
include/coap/coap_dtls.h
Outdated
uint8_t check_cert_revocation; /**< 1 if revocation checks wanted */ | ||
uint8_t allow_no_crl; /**< 1 ignore if CRL not there */ | ||
uint8_t allow_expired_crl; /**< 1 if expired crl is allowed */ | ||
uint8_t reserved[6]; /**< Reserved - set to 0 - causes |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any reason why we do not rely on the compiler to do the alignment?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By having the reserved defined, they can then be used later for additional options without breaking the coap_dtls_pki_t overall size/order breaking old code using a newer library, so I would prefer it to be left 'as is'. Comment on reserved updated.
include/coap/coap_dtls.h
Outdated
* If not NULL, then application is handling the characteristics of the TLS | ||
* connection setup in the defined call-back handler. If set, then none of | ||
* the options or call-backs above are acted on. */ | ||
coap_dtls_security_setup_t full_call_back; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we change the field name here? This is not very self-explanatory:
coap_dtls_pki_t pki;
pki.full_call_back = func;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renamed to app_override_tls_setup_call_back.
src/coap_openssl.c
Outdated
/* Add CA to the trusted root CA store */ | ||
st = SSL_CTX_get_cert_store(ctx); | ||
/* Flush out existing errors */ | ||
while ((e = ERR_get_error()) != 0) { } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For better readability, please move the closing parenthesis to the next line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
|
||
/* We do not add CA for client to send to client as we are client! */ | ||
|
||
/* Add CA to the trusted root CA store */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There seems to be a lot of duplicate code here. I suggest factoring it out into a separate function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed by making use of a common function add_ca_to_cert_store()
src/coap_openssl.c
Outdated
} | ||
/* Otherwise look for the CN= field */ | ||
X509_NAME_oneline(X509_get_subject_name(x509), buffer, sizeof(buffer)); | ||
cn = strcasestr(buffer, "CN="); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
strcasestr()
is a nonstandard extension. The idea is to keep these out of the core library.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed by using local equivalent
src/coap_openssl.c
Outdated
return context->psk_pki_enabled; | ||
} | ||
|
||
|
||
void coap_dtls_free_context(void *handle) { | ||
int i; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be of type size_t
or so in alignment with `context->sni_count.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
src/coap_session.c
Outdated
@@ -631,33 +632,43 @@ coap_session_t *coap_new_client_session_psk( | |||
if (!session) | |||
return NULL; | |||
|
|||
if (identity) { | |||
if (identity && strlen(identity) > 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please enclose the comparison in parentheses as always.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed. Brain is not always fully in gear when different projects have different coding styles!
Just did a rebase on develop push - none of the comments have yet been addressed. |
To enable early detection of a TCP connection failure. Tidy up linelength of some surrounding functions.
coap_dtls_pki_t struct has been enhanced to have more configuration options. These configuruation options then tell libcoap what needs to get checked by the underlying OpenSSL library rather than the user application has to do it. There still is support for the user application to do all the Certificate checking etc. A late change to the PKI Pull request got missed for the TLS case in coap_dtls_context_set_pki() for the mapping of private key types to the OpenSSL version. Have now pulled common DTLS and TLS code into a seperate function Fixed coap_(d)tls_free_session to not shut down a session that is not yet fully started, as well as calling SSL_shutdown() twice if appropriate The ssl parameter is set to NULL after closedown Made coap_dtls_context_set_psk() smarter in what was updated, depending on whether called by a client or server Make sure that coap_dtls_psk_client_callback is defined in coap_dtls_context_set_psk() in case coap_dtls_context_set_pki() was called first. This fixes the first time issue after startup where a PSK client was unable to establish a DTLS session - subsequent times were successful Added in a set of callbacks, invoked from coap_dtls_context_set_pki(), so that a server can differentiate between an incoming PSK or PKI connection request. These are only invoked if no full_call_back was defined in the setup_data Add in a set of user definable callbacs for checking CN and SNI provided information Add in support for the generation and detection of ALPN externsion Output error message if PKI or PSK was not set up before a server endpoint was set up and (D)TLS is being used. Allow a client to talk to a server that is PKI enabled without the need for a PreShared Key or PKI Certificate Set the SSL information at the SSL, not the CTX level when it is a client
…dtls_pki_t coap_context_set_pki_root_cas(): New coap_dtls_context_set_psk(): remove unused parameters, add in server parameter coap_dtls_context_set_pki(): add in server parameter coap_dtls_pki_t: Additional configuration parameters coap_dtls_security_setup_t: Updated coap_dtls_cn_callback_t: New coap_dtls_sni_callback_t: New coap_pki_key_t: New coap_pki_key_pem_t: New coap_pki_key_asn1_t: New coap_dtls_sni_t: New Comments tidy up. Better Doxygen comments for coap_dtls.h and net.h Doxygen fix for debug.h (introduced by obgm#219 merge) Doxygen update coap_endpoint_new_dtls_session() for in coap_session.h
…*() functions coap_dtls_context_set_pki_root_cas(): New function coap_dtls_context_set_psk(): Remove unused parameters, add in server parameter coap_dtls_context_set_pki(): Add in server parameter coap_dtls_context_check_keys_enabled(): Add in UNUSED src/coap_tinydtls.c: coap_dtls_free_session() set coap_session->tls = NULL
…ions Update calls to coap_dtls_context_set_*() functions "\n" terminate coap_log() calls src/coap_session.c: coap_session_disconnected() Report the session disconnected reason Warn if coap_new_client_session_psk() called without both key and identity defined (OpenSSL cannot handle this) src/net.c: coap_context_set_pki_root_cas(): New function
Code pushed, rebased off develop. Only change not made is whether the asn1_ prefix should really be asn1der_. |
examples/coap-server.c
Outdated
dtls_pki.pki_key.key.pem.ca_file = ca_file; | ||
/* If general root CAs are defined */ | ||
if (root_ca_file) { | ||
coap_context_set_pki_root_cas(ctx, root_ca_file, NULL); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
During testing, I found it very useful to specify a directory such as /etc/ssl/certs
like this:
diff --git a/examples/coap-server.c b/examples/coap-server.c
index 5f9d2c7..5f75009 100644
--- a/examples/coap-server.c
+++ b/examples/coap-server.c
@@ -389,7 +389,12 @@ fill_keystore(coap_context_t *ctx) {
dtls_pki.pki_key.key.pem.ca_file = ca_file;
/* If general root CAs are defined */
if (root_ca_file) {
- coap_context_set_pki_root_cas(ctx, root_ca_file, NULL);
+ struct stat stbuf;
+ if ((stat(root_ca_file, &stbuf) == 0) && S_ISDIR(stbuf.st_mode)) {
+ coap_context_set_pki_root_cas(ctx, NULL, root_ca_file);
+ } else {
+ coap_context_set_pki_root_cas(ctx, root_ca_file, NULL);
+ }
}
coap_context_set_pki(ctx, &dtls_pki);
if (key_defined)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I like that change.
Code pushed - done change in client as well as man pages / usage(). |
man/coap_encryption.txt.in
Outdated
coap_encryption(3) | ||
=================== | ||
:doctype: manpage | ||
:man source: coap_tls_library |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be :man source: coap_encryption
, I suppose.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The joys copying files and using them as templates! Fixed.
to provide a PSK. The Server must have a Hint defined and the Client must | ||
have an Identity defined. | ||
|
||
For PKI setup, if the libcoap PKI configuration options do not handle a specific |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if we could also give an example for RPK usage?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not entirely sure after investigation that OpenSSL 1.1.0 properly supports RPK, but am willing to be proven wrong. Does tinyDTLS support this as an alternative?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, TinyDTLS supports RPK (and only RPK, no full-fledged PKI).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reason you might want asymmetric cryptography but not check certificate chains (consider 150 or so root CAs stored in a class 1 IoT device...)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fully understand why RPK makes sense, need it for the DOTS protocol. However https://en.wikipedia.org/wiki/Comparison_of_TLS_implementations confirms my suspicion of OpenSSL as unknown. My guess is that RPK would be done using the asn1 variant.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was specifically concerned about the API. I would expect to use RPKs in libcoap similar to full X.509 certificates but without transitive trust. The root CA files then pretty much would be the known RPKs, and the certfiles an RPK instead of a full certificate. (All being DER-encoded ASN.1 structures.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The right way forward here is to add in coap_context_set_rpk() and coap_new_client_session_rpk() for RPK support. This has 2 benefits
- The server can support all 3 of PSK. PKI and RPK concurrently, so the client can choose any of the 3 methods
- RPK can then use the TinyDTLS support for RPK.
The functions would be modeled on the *_pki() equivalent, but the setup_data parameter would be different. I would expect setup_data to contain a parameter pointing to a directory containing the known RPKs.
This would be done under a new PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, sounds reasonable to me. I suppose, this would be somehow related to PR #128.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I was planning to use what made sense out of #128 with these new functions for TinyDTLS.
Split out old coap_context(3) into coap_context(3), coap_encryption(3) and coap_session(3) with coap_encryption(3) primarily updated to reflect the updated PKI configuration options. coap-client.txt.in coap-server.txt.in Update with new options making use of updated PKI interface
Also, remove coap_endpoint_new_dtls_session() as it is an internal function
Also, exclude coap_endpoint_new_dtls_session() as it is an internal function
Push with man/coap_encryption.txt.in typo fixed. |
Commit e1fbd15 has a typo in its commit message (s/mutial/mutual/). If you want to fix that, I will wait for it, otherwise, I see this PR ready for merge. Awesome work! |
Updated to support the new coap_dtls_pki_t. Add in new -C and -R options to support / test PKI mutual authentication Make sure time resource is triggered no more frequently than once a sec.
Commit typo corrected. |
A late change to the PKI Pull request got missed for the TLS case
in coap_dtls_context_set_pki() for the mapping of private key types to
the OpenSSL version. Have pulled common DTLS and TLS code into a separate
function
Fixed coap_(d)tls_free_session to not shut down a session that is not yet
fully started, as well as calling SSL_shutdown() twice if appropriate.
The ssl parameter is set to NULL after shutdown to prevent re-use
Made coap_dtls_context_set_psk() smarter in what whas updated, depending on
whether a client or server
Make sure that coap_dtls_psk_client_callback is defined in
coap_dtls_context_set_psk() in case coap_dtls_context_set_pki() was called
first. This fixes the first time issue after startup where a PSK client
was unable to establish a DTLS session - subsequent times were successful
Added in a set of callbacks, invoked from coap_dtls_context_set_pki(), so that
a server can differentiate between an incoming PSK or PKI connection request.
These are only invoked if no call_back was defined in the setup_data
Output error messages if PKI or PSK was not set up before a server endpoint was
set up and (D)TLS is being used.
Update internal coap_dtls_context_set_*() functions parameters to remove unused parameters and add in a server parameter
Add in TCP KeepAlive to TCP socket to pick up on failing TCP connections