Read certificate files from memory instead of a file using OpenSSL

后端 未结 4 1050
遇见更好的自我
遇见更好的自我 2020-12-09 04:59

I have a server which would listen on HTTPS using OpenSSL. For this, I have to provide the certificate to use. However, the current implementation uses a filename to be prov

相关标签:
4条回答
  • 2020-12-09 05:26

    There is another response that uses X509_STORE_add_cert, which is up-voted but incorrect. That answer is a way to do SSL_CTX_load_verify_locations in memory, but does not load the server certificate chain. Replies to that comment also indicate that it does not work.

    The following code is a load-from-memory implementation of SSL_CTX_use_certificate_chain_file based on the implementation of that function in OpenSSL:

    bool load_cert_chain_from_shared_mem(SSL_CTX *context, const char *cert_buffer)
    {
        BIO *cbio = BIO_new_mem_buf((void*)cert_buffer, -1);
        if (!cbio)
            return false;
    
        X509_INFO *itmp;
        int i, count = 0, type = X509_FILETYPE_PEM;
        STACK_OF(X509_INFO) *inf = PEM_X509_INFO_read_bio(cbio, NULL, NULL, NULL);
    
        if (!inf)
        {
            BIO_free(cbio);
            return false;
        }
    
        /* Iterate over contents of the PEM buffer, and add certs. */
        BOOL first = TRUE;
        for (i = 0; i < sk_X509_INFO_num(inf); i++) {
            itmp = sk_X509_INFO_value(inf, i);
            if (itmp->x509)
            {
                /* First cert is server cert. Remaining, if any, are intermediate certs. */
                if (first)
                {
                    first = FALSE;
    
                    /*
                     * Set server certificate. Note that this operation increments the
                     * reference count, which means that it is okay for cleanup to free it.
                     */
                    if (!SSL_CTX_use_certificate(context, itmp->x509))
                        goto Error;
    
                    if (ERR_peek_error() != 0)
                        goto Error;
    
                    /* Get ready to store intermediate certs, if any. */
                    SSL_CTX_clear_chain_certs(context);
                }
                else
                {
                    /* Add intermediate cert to chain. */
                    if (!SSL_CTX_add0_chain_cert(context, itmp->x509))
                        goto Error;
    
                    /*
                     * Above function doesn't increment cert reference count. NULL the info
                     * reference to it in order to prevent it from being freed during cleanup.
                     */
                    itmp->x509 = NULL;
                }
            }
        }
    
        sk_X509_INFO_pop_free(inf, X509_INFO_free);
        BIO_free(cbio);
    
        return true;
    
    Error:
        sk_X509_INFO_pop_free(inf, X509_INFO_free);
        BIO_free(cbio);
    
        return false;
    }
    
    0 讨论(0)
  • 2020-12-09 05:31

    The following code did the job for me:

     
    SSL_CTX *CTX;
    X509 *cert = NULL;
    RSA *rsa = NULL;
    BIO *cbio, *kbio;
    const char *cert_buffer = "";
    const char *key_buffer = "";
    
    cbio = BIO_new_mem_buf((void*)cert_buffer, -1);
    cert = PEM_read_bio_X509(cbio, NULL, 0, NULL);
    assert(cert != NULL);
    SSL_CTX_use_certificate(CTX, cert);
    
    kbio = BIO_new_mem_buf((void*)key_buffer, -1);
    rsa = PEM_read_bio_RSAPrivateKey(kbio, NULL, 0, NULL);
    assert(rsa != NULL);
    SSL_CTX_use_RSAPrivateKey(CTX, rsa);
    
    0 讨论(0)
  • 2020-12-09 05:32
    unsigned char *cert_data = (....);
    int cert_len = (....);
    
    X509 *cert = d2i_X509(NULL, &cert_data, cert_len);
    SSL_CTX_use_certificate(ctx, cert);
    
    unsigned char *pkey_data = /* ... */;
    int pkey_len = /* ... */;
    
    RSA *pkey = d2i_RSAPrivateKey(NULL, &pkey_data, pkey_len);
    SSL_CTX_use_RSAPrivateKey(ctx, pkey);
    

    Don't forget & before cert_data and pkey_data - and note that OpenSSL modifies these pointers.

    0 讨论(0)
  • 2020-12-09 05:41

    The other snippets will only load one certificate. The content of files like http://curl.haxx.se/ca/cacert.pem that contain a lot of different certificates need a new approach. This is adapted from openssl 1.0.1p (mostly openssl-1.0.1p\crypto\x509\by_file.c, char* buf contains the content of a *.pem file, ctx is a boost::asio::ssl::context), add error handling on your own:

    BIO *cbio = BIO_new_mem_buf((void*)buf, (int)length);
    X509_STORE  *cts = SSL_CTX_get_cert_store(ctx.native_handle());
    if(!cts || !cbio)
       return false;
    X509_INFO *itmp;
    int i, count = 0, type = X509_FILETYPE_PEM;
    STACK_OF(X509_INFO) *inf = PEM_X509_INFO_read_bio(cbio, NULL, NULL, NULL);
    
    if (!inf)
    {
        BIO_free(cbio);//cleanup
        return false;
    }
    //itterate over all entries from the pem file, add them to the x509_store one by one
    for (i = 0; i < sk_X509_INFO_num(inf); i++) {
        itmp = sk_X509_INFO_value(inf, i);
        if (itmp->x509) {
              X509_STORE_add_cert(cts, itmp->x509);
              count++;
        }
        if (itmp->crl) {
              X509_STORE_add_crl(cts, itmp->crl);
              count++;
        }
    }
    sk_X509_INFO_pop_free(inf, X509_INFO_free); //cleanup
    BIO_free(cbio);//cleanup
    
    0 讨论(0)
提交回复
热议问题