Thursday, August 24, 2017

Usage difference between SSL_add0_chain_cert and SSL_add1_chain_cert?

Leave a Comment

In OpenSSL documentation it says:

All these functions are implemented as macros. Those containing a 1 increment the reference count of the supplied certificate or chain so it must be freed at some point after the operation. Those containing a 0 do not increment reference counts and the supplied certificate or chain MUST NOT be freed after the operation.

But when I tried to look at examples of cases about which one should be used where I'm confused.

First OpenSSL:

It uses SSL_add0_chain_cert itself in the SSL_CTX_use_certificate_chain_file function of ssl_rsa.c. Here is the source:

static int use_certificate_chain_file(SSL_CTX *ctx, SSL *ssl, const char *file) {     if (ctx)         ret = SSL_CTX_use_certificate(ctx, x);     else         ret = SSL_use_certificate(ssl, x);     ......     while ((ca = PEM_read_bio_X509(in, NULL, passwd_callback,                                    passwd_callback_userdata))            != NULL) {         if (ctx)             r = SSL_CTX_add0_chain_cert(ctx, ca);         else             r = SSL_add0_chain_cert(ssl, ca);     ...... } 

Second usage I see is OpenResty Lua:

It uses SSL_add0_chain_cert in one way of setting certificate (ngx_http_lua_ffi_ssl_set_der_certificate), see here:

int ngx_http_lua_ffi_ssl_set_der_certificate(ngx_http_request_t *r, const char *data, size_t len, char **err) {     ......     if (SSL_use_certificate(ssl_conn, x509) == 0) {         *err = "SSL_use_certificate() failed";         goto failed;     }     ......     while (!BIO_eof(bio)) {          x509 = d2i_X509_bio(bio, NULL);         if (x509 == NULL) {             *err = "d2i_X509_bio() failed";             goto failed;         }          if (SSL_add0_chain_cert(ssl_conn, x509) == 0) {             *err = "SSL_add0_chain_cert() failed";             goto failed;         }     }      BIO_free(bio);      *err = NULL;     return NGX_OK; failed:     ....... } 

Yet uses SSL_add1_chain_cert in another way (ngx_http_lua_ffi_set_cert), see here:

int ngx_http_lua_ffi_set_cert(ngx_http_request_t *r,     void *cdata, char **err) {     ......     if (SSL_use_certificate(ssl_conn, x509) == 0) {         *err = "SSL_use_certificate() failed";         goto failed;     }      x509 = NULL;      /* read rest of the chain */      for (i = 1; i < sk_X509_num(chain); i++) {          x509 = sk_X509_value(chain, i);         if (x509 == NULL) {             *err = "sk_X509_value() failed";             goto failed;         }          if (SSL_add1_chain_cert(ssl_conn, x509) == 0) {             *err = "SSL_add1_chain_cert() failed";             goto failed;         }     }      *err = NULL;     return NGX_OK; /* No free of x509 here */  failed: ...... } 

Yet I don't see a clear difference of what changes when calling these two in Lua, and it doesn't seem like the cert X509, when set successfully, gets freed in either case. According to my understanding of the OpenSSL doc, I should expect X509_free(x509) gets called somewhere after SSL_add1_chain_cert called on that x509. Is that the correct understanding?

Last, the Openssl implementation of ssl_cert_add1_chain_cert (what boils down from SSL_add1_chain_cert macro) does indeed show it's just a wrapper of ssl_cert_add0_chain_cert with reference count incremented on the cert, but how should that be reflected in the calling process?

int ssl_cert_add1_chain_cert(SSL *s, SSL_CTX *ctx, X509 *x) {     if (!ssl_cert_add0_chain_cert(s, ctx, x))         return 0;     X509_up_ref(x);     return 1; } 

Now Nginx only deals with another function SSL_CTX_add_extra_chain_cert which leaves the burden of such choice behind, as it does not deal with switching cert per SSL connection basis. In my case I need to patch Nginx with this capability, switching cert per connection (but without using Lua).

So I'm not sure which one I should be using, SSL_add0_chain_cert or SSL_add1_chain_cert? And what's the freeing practice here?

0 Answers

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment