openssl 读取各种密钥的方法和接口

在用openssl读取密钥的时候,从openssl的源码的找到一个很好的示例,完美的示范了读不同格式,不同密钥来源的程序,整理一下,用来学习是相当不错
完整的代码位于…/apps/app.c中
函数是

EVP_PKEY *load_key(BIO *err,const char *file,int format,int maybe_stdin,const char *pass,ENGINE *e,const char *key_descript)
{
    const SSL_METHOD *meth;

    meth = SSLv23_client_method();
    //meth = TLSv1_client_method();

    OpenSSL_add_ssl_algorithms();
    SSL_load_error_strings();

    //参数1:错误输出 bio,一般就是stderr了
    //
    BIO *bio_err = NULL;
    if(bio_err == NULL)
        bio_err = BIO_new_fp(stderr,NIO_MOCLOSE);
    //参数2 : 密钥文件名字,可以是pem,der,pfx,或者engine中key的label
    char *key_file = NULL;
    //参数3 : 密钥格式
    int key_format = FORMAT_PEM;    //openssl中默认一般都是 PEM格式
                                    //FORMAT_TEXT
                                    //FORMAT_ASN1
                                    //FORMAT_PKCS12
                                    //FORMAT_PEMRSA
                                    //FORMAT_ASN1RSA
                                    //FORMAT_ENGINE
    //参数4:密钥来自非文件(stdin)
    int key_stdin = 0;
    //参数5:密钥的密码 
    char *passarg = NULL;   //参数,可能来自文件,也可能直接是密码
                            // pass:
                            // env:
                            // file:
                            // fd:
                            // stdin:
    char *pass = NULL;      //解析出来的密码字串
    //参数6:engine
    char *engine_id = NULL; //engine的名字
    ENGINE *e = NULL;
    e = ENGINE_by_id(engine_id);
    //e = try_load_engine(bio_err,engine_id,debug);
    ENGINE_set_default(e,ENGINE_METHOD_ALL);

    //参数7:密钥的描述
    const char *key_descript = "client certificate private key file";

    //EVP_PKEY *load_key(BIO *err,const char *file,int format,int maybe_stdin,
    //      const char *pass,ENGINE *e,const char *key_descript)

    //好,现在来读密钥

    EVP_PKEY *key = NULL;
    key = load_key(bio_err,key_file,key_format,key_stdin,pass,e,key_descript);

    /****************************************************************/
    //开始分析过程
    {
        PW_CB_DATA cb_data;
        cb_data.password = pass;
        cb_data.prompt_info = file;

        BIO *key = NULL;
        EVP_PKEY *pkey = NULL;

        //key必须来自file,stdin,engine中的一种
        if(engine) //engine
        {
            pkey = ENGINE_load_private_key(e,key_file,ui_method,&cb_data);
            goto end;

        }

        key=BIO_new(BIO_s_file());
        if(key_stdin)   //stdin
        {
            BIO_set_fp(key,stdin,BIO_NOCLOSE);
        }
        else(key_file)      //file
        {
            BIO_read_filename(key,key_file)
        }

        //格式转换
        if(format == FORMAT_ASN1)   //der
        {
            pkey = d2i_PrivateKey_bio(key,NULL);
        }
        else if(format == FORMAT_PEM)   //pem
        {
            pkey = PEM_read_bio_PrivateKey(key,NULL,
                    (pem_password_cb *)password_callback,&cb_data);
        }
        else if(format == FORMAT_PKCS12)    //p12
        {
            //这个过程比较多,还是参考源码,我只给出流程和常用函数
            //load_pkcs12()
            {
                PKCS12 *p12;
                char *pass;
                p12 = d2i_PKCS12_bio(key,NULL);
                if(PKCS12_verify_mac(p12,"",0) || PKCS12_verify_mac(p12,NULL,0))
                {
                    pass = "";
                }else
                {
                    PKCS12_verify_mac(p12,tpass,len)
                }

                //最后,PKCS12可以从p12文件中解析出pkey,cert,ca
                ret = PKCS12_parse(p12,pass,pkey,cert,ca);
                //释放
                if(p12)
                    PKCS12_free(p12);

            }
        }else
        {
            //其他格式的解析,源码里都有,不常用就不列出来了
        }

        return pkey;

    }


    //获取密钥后将密钥填充到ssl 的 ctx中
    SSL_CTX *ctx = NULL;
    ctx = SSL_CTX_new(meth);
    SSL_CTX_use_PrivateKey(ctx,key);

    //在填充了证书之后往往还会检查证书公钥与私钥是否匹配
    SSL_CTX_check_private_key(ctx); 

    SSL *con = NULL;
    con = SSL_new(ctx);
}

说明:
1.在这段代码中出现的部分结构不存在openssl的标准头文件中,而是在app.h或者其他文件中
2.当然,openssl也提供了如

SSL_CTX_use_PrivateKey_file(ctx,"client.key",SSL_FILETYPE_PEM);
    //SSL_FILETYPE_PEM
    //SSL_FILETYPE_ASN1
这样的调用,但是好像只支持 x509的证书

//也有设置密码的接口
SSL_CTX_set_default_passwd_cb_userdata()

你可能感兴趣的:(学习)