diff --git a/CHANGES b/CHANGES index 34908a34873f6855ffc9464bbd5be47dcd5b7d4f..97fb723fc33e98cc538c41158372aa70f99b0254 100644 --- a/CHANGES +++ b/CHANGES @@ -5,6 +5,12 @@ Changes between 0.9.2b and 0.9.3 + *) New function SSL_CTX_use_certificate_chain_file that sets the + "extra_cert"s in addition to the certificate. (This makes sense + only for "PEM" format files, as chains as a whole are not + DER-encoded.) + [Bodo Moeller] + *) Support verify_depth from the SSL API. x509_vfy.c had what can be considered an off-by-one-error: Its depth (which was not part of the external interface) diff --git a/ssl/ssl.h b/ssl/ssl.h index b041341ba5bb09c8be61a0b973254bf00061ce10..0f4fbe8e23b38a17ed39dfc5fb66f8191bb6e6d7 100644 --- a/ssl/ssl.h +++ b/ssl/ssl.h @@ -874,6 +874,7 @@ int SSL_use_certificate_file(SSL *ssl, char *file, int type); int SSL_CTX_use_RSAPrivateKey_file(SSL_CTX *ctx, char *file, int type); int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, char *file, int type); int SSL_CTX_use_certificate_file(SSL_CTX *ctx, char *file, int type); +int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file); /* PEM type */ STACK_OF(X509_NAME) *SSL_load_client_CA_file(const char *file); int SSL_add_file_cert_subjects_to_stack(STACK *stackCAs, const char *file); @@ -1168,6 +1169,7 @@ int SSL_COMP_add_compression_method(int id,char *cm); #define SSL_F_SSL_CTX_SET_SSL_VERSION 170 #define SSL_F_SSL_CTX_USE_CERTIFICATE 171 #define SSL_F_SSL_CTX_USE_CERTIFICATE_ASN1 172 +#define SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE 220 #define SSL_F_SSL_CTX_USE_CERTIFICATE_FILE 173 #define SSL_F_SSL_CTX_USE_PRIVATEKEY 174 #define SSL_F_SSL_CTX_USE_PRIVATEKEY_ASN1 175 diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c index 3d9a83517b89ddef4c1cd37f4e0d2db4d78c0d7e..eae7ad7db1e3ac42a3bcde341a2f12baeb8238a0 100644 --- a/ssl/ssl_err.c +++ b/ssl/ssl_err.c @@ -142,6 +142,7 @@ static ERR_STRING_DATA SSL_str_functs[]= {ERR_PACK(0,SSL_F_SSL_CTX_SET_SSL_VERSION,0), "SSL_CTX_set_ssl_version"}, {ERR_PACK(0,SSL_F_SSL_CTX_USE_CERTIFICATE,0), "SSL_CTX_use_certificate"}, {ERR_PACK(0,SSL_F_SSL_CTX_USE_CERTIFICATE_ASN1,0), "SSL_CTX_use_certificate_ASN1"}, +{ERR_PACK(0,SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE,0), "SSL_CTX_USE_CERTIFICATE_CHAIN_FILE"}, {ERR_PACK(0,SSL_F_SSL_CTX_USE_CERTIFICATE_FILE,0), "SSL_CTX_use_certificate_file"}, {ERR_PACK(0,SSL_F_SSL_CTX_USE_PRIVATEKEY,0), "SSL_CTX_use_PrivateKey"}, {ERR_PACK(0,SSL_F_SSL_CTX_USE_PRIVATEKEY_ASN1,0), "SSL_CTX_use_PrivateKey_ASN1"}, diff --git a/ssl/ssl_rsa.c b/ssl/ssl_rsa.c index a2db46e05f2cb60e17bc6601c253dff4c54cfb1b..0f87752217bc688ac5f9a80188c5718e15f8d134 100644 --- a/ssl/ssl_rsa.c +++ b/ssl/ssl_rsa.c @@ -735,3 +735,81 @@ int SSL_CTX_use_PrivateKey_ASN1(int type, SSL_CTX *ctx, unsigned char *d, } +#ifndef NO_STDIO +/* Read a file that contains our certificate in "PEM" format, + * possibly followed by a sequence of CA certificates that should be + * sent to the peer in the Certificate message. + */ +int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file) + { + BIO *in; + int ret=0; + X509 *x=NULL; + + in=BIO_new(BIO_s_file_internal()); + if (in == NULL) + { + SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE,ERR_R_BUF_LIB); + goto end; + } + + if (BIO_read_filename(in,file) <= 0) + { + SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE,ERR_R_SYS_LIB); + goto end; + } + + x=PEM_read_bio_X509(in,NULL,ctx->default_passwd_callback); + if (x == NULL) + { + SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE,ERR_R_PEM_LIB); + goto end; + } + + ret=SSL_CTX_use_certificate(ctx,x); + if (ERR_peek_error() != 0) + ret = 0; /* Key/certificate mismatch doesn't imply ret==0 ... */ + if (ret) + { + /* If we could set up our certificate, now proceed to + * the CA certificates. + */ + X509 *ca; + int r; + unsigned long err; + + if (ctx->extra_certs != NULL) + { + sk_X509_pop_free(ctx->extra_certs, X509_free); + ctx->extra_certs = NULL; + } + + while ((ca = PEM_read_bio_X509(in,NULL,ctx->default_passwd_callback)) + != NULL) + { + r = SSL_CTX_add_extra_chain_cert(ctx, ca); + if (!r) + { + X509_free(ca); + ret = 0; + goto end; + } + /* Note that we must not free r if it was succesully + * added to the chain (while we must free the main + * certificate, since its reference count is increased + * by SSL_CTX_use_certificate). */ + } + /* When the while loop ends, it's usually just EOF. */ + err = ERR_peek_error(); + if (ERR_GET_LIB(err) == ERR_LIB_PEM && ERR_GET_REASON(err) == PEM_R_NO_START_LINE) + (void) ERR_get_error(); + else + ret = 0; /* some real error */ + } + +end: + if (x != NULL) X509_free(x); + if (in != NULL) BIO_free(in); + return(ret); + } +#endif