openssl从内存加载证书、私钥、证书链

概述

在使用openssl建立ssl/tls连接时,需要加载对端的证书链,自己的证书以及私钥。本文主要描述如何从文件以及内存中加载通信对端的证书链、自己的证书以及私钥(RSA证书ECC证书通用)。

PS:为什么要从内存中加载私钥?私钥是要求安全存储的,通常是存储到软的密钥存储或者专用的安全硬件中,不会明文落盘,所以应用是无法从磁盘上读取到明文的私钥文件的。

1.加载证书链

加载证书链有三种方式:(1)指定证书链所在的文件夹路径(2)指定证书链文件(把证书链cat 到一个文件内)(3)从内存中加载证书链。
前两种方式都有现成的接口SSL_CTX_load_verify_locations,而从内存中加载证书链,稍微麻烦一点儿,不过网络上已经有很多的文章,通过gdb跟踪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;         
    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;  
}  

2.加载证书

从文件中加载证书: SSL_CTX_use_certificate_file
从内存中加载证书:

static X509* buffer2x509(const uint8_t* cert, size_t len) {  
    /*read the cert and decode it*/   
    BIO *b = BIO_new_mem_buf((void *)cert, len);  
    if (NULL == b) { 
        return NULL;     
    }      
    X509* x509 = PEM_read_bio_X509(b, NULL, NULL, NULL);          
    if (NULL == x509) {         
        BIO_free(b);          
        return NULL;          
    }                  
    BIO_free(b);            
    return x509;           
}        

3.加载私钥

从文件中加载私钥:SSL_CTX_use_PrivateKey_file
从内存中加载私钥:

static EVP_PKEY* buffer2evpkey(const uint8_t* key, size_t key_len) {    
    BIO *b = BIO_new_mem_buf((void *)key, key_len);                     
    if (NULL == b) {                        
        return NULL;                        
    } 
	
	//如果私钥文件使用了密码进行了加密,则下面函数的第二个和第三个入参要赋值,具体请参见openssl的PEM_read_bio_PrivateKey接口描述
    EVP_PKEY* evpkey = PEM_read_bio_PrivateKey(b, NULL, NULL, NULL);    
    if (NULL == evpkey) {                   
        BIO_free(b);                        
        return NULL;                        
    }           
    BIO_free(b);
    return evpkey;                          
}    

从内存中加载证书和私钥的方法并不仅有上文描述的方式,还有其他的方式,比如RSA私钥可以通过构建RSA结构来加载,ECC私钥可以通过构建EC_KEY结构的方式来加载,不过个人觉得上面的方法更为通用。

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值