The OpenSSL documentation says:
All these functions are implemented as macros. Those that contain 1 increment of the reference counter of the attached certificate or chain, so it must be released at some point after the operation. Those containing 0 do not increase the number of links, and the attached certificate or chain MUST NOT be released after the operation.
But when I tried to look at examples of cases that should be used, where I got confused.
First OpenSSL :
It uses SSL_add0_chain_cert directly in the SSL_CTX_use_certificate_chain_file function 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); ...... }
The second use I see is OpenResty Lua :
It uses SSL_add0_chain_cert one way to install the 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: ....... }
But uses SSL_add1_chain_cert differently ( 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; 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; failed: ...... }
However, I donโt see a clear difference in what changes are caused when these two are called in Lua , and it does not look like the X509 certificate, when it is installed successfully, is released anyway. According to my understanding of the OpenSSL document, I should expect X509_free(x509) be called somewhere after the SSL_add1_chain_cert caused by this x509. Is this the correct understanding?
Finally, the Openssl implementation of ssl_cert_add1_chain_cert (which boils down to the SSL_add1_chain_cert macro) does show it as a ssl_cert_add0_chain_cert with reference counts increased by cert, but how should this affect 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 works with another SSL_CTX_add_extra_chain_cert function, which leaves the burden of such a choice behind since it does not deal with certificate switching based on SSL connection. In my case, I need to install Nginx with this feature, switching the certificate to the connection (but without using Lua).
So I'm not sure which one should I use, SSL_add0_chain_cert or SSL_add1_chain_cert ? What is liberation practice here?