【问题标题】:Modifying extension list in X509 certificate using OpenSSL in C在 C 中使用 OpenSSL 修改 X509 证书中的扩展列表
【发布时间】:2021-11-11 06:52:09
【问题描述】:

我正在尝试将已签名的 sct 插入到具有毒扩展名的预证书中。 所以我首先删除毒扩展,然后添加 SCT。 这就是我所做的:

int main(int argc, char **argv) {
    size_t lenCert = 0, lenCert2 = 0;
    char *filePEM  = "testpem/precert3.cert.pem";
    char *strCertPem = loadFileContent(filePEM, &lenCert);
    const X509 *cert = parse_certificate(strCertPem);
    X509 *certRef = X509_dup(cert);

    if(!cert || cert==NULL){
        printf("Failed parsing\n");
        return -1;
    }

    int len_init = -1;
    unsigned char *buf_init = NULL;
    len_init = i2d_X509(certRef, &buf_init);

    if(len_init < 0){
        printf("INIT: failed conversion to DER\n");
        return -1;
    } else {
        printf("INIT: Successful conversion to DER[%d]\n", len_init);
    }


    printf("size certificate: %ld\n", lenCert);
    X509_EXTENSION *tmpext;
    const STACK_OF(X509_EXTENSION) *allExt = X509_get0_extensions(cert);
    const STACK_OF(X509_EXTENSION) *allExt2 = X509_get0_extensions(certRef);
    int my_idx = X509v3_get_ext_by_NID(allExt, NID_ct_precert_poison, -1);
    int idx = my_idx;
    int cc = X509_get_ext_count(cert);
    printf("Extension count in cert BEFORE = %d\n", cc);

    printf((allExt==NULL) ? "Extensions extraction FAILED\n" : "Extensions extraction SUCCESS\n");

    int counter = X509v3_get_ext_count(allExt);
    printf("Extension[%d] count BEFORE = %d\n", idx, counter);

    do {
        tmpext = X509v3_get_ext(allExt, idx);
        X509v3_delete_ext(allExt, idx);
        X509_EXTENSION_free(tmpext);
        idx = X509v3_get_ext_by_NID(allExt, NID_ct_precert_poison, -1);
        printf("pass\n");
    } while (idx != -1);

    counter = X509v3_get_ext_count(allExt);
    printf("Extension count AFTER = %d\n", counter);

    if(X509_cmp( cert, certRef)){
        printf("Certificate modified\n\n");
    } else {
        printf("FAILED!!! \n");
    }

    cc = X509_get_ext_count(cert);
    printf("Extension count in cert AFTER = %d\n", cc);

    int len_inter;
    unsigned char *buf_inter = NULL;
    len_inter = i2d_X509(cert, &buf_inter);
    if(len_inter < 0){
        printf("INTERMEDIATE: failed conversion to DER\n");
        return -1;
    } else {
        printf("INTERMEDIATE: Successful conversion to DER[%d]\n", len_inter);
    }

    unsigned char *dersct;
    size_t lenSCTList = 0;
    char *b64SCTList = "BIF6AHgAdgCwzIPlpfl9a698CcwoSQSHKsfoixMsY1C3xv0m4WxsdwAAAWZ7z/DQAAAEAwBHMEUCIQDKJPPQhWqje1rQq+T06x0iNlLT7rX71k23VPZkhm/QCwIgfhwNK7izeq0fHAlu7HuYRjmvym51RRdlNWhd50LQdu4=";
    int b64Res = Base64Decode(b64SCTList, &dersct, &lenSCTList); //Decodes a base64 encoded string
    printf("size final SCT List: %ld\n", lenSCTList);

    STACK_OF(SCT) * scts = d2i_SCT_LIST(NULL, (const unsigned char **) &dersct, lenSCTList);
    if(scts==NULL){
        printf("Could not convert SCT List!");
        return -1;
    } 
    printf("SCT List converted !\n");
    ASN1_OCTET_STRING   *val   = ASN1_OCTET_STRING_new();
    ASN1_OCTET_STRING_set(val, dersct, (int)lenSCTList);
    X509_EXTENSION* extSCT = X509_EXTENSION_create_by_NID(NULL, NID_ct_precert_scts, 0, val);

    if(extSCT){
        printf("created extension\n");
    } else {
        printf("Failed to create extension\n");
        return -1;
    }

    if( X509_add_ext(cert, extSCT, -1)) {
        printf("Extension added\n");
       //  X509_EXTENSION_free(extSCT);

    } else {
        printf("failed to add extension\n");
        return -1;
    }
    int len_final;
    unsigned char *buf_final = NULL;
    len_final = i2d_X509(cert, &buf_final);
    if(len_final < 0){
        printf("FINAL: failed conversion to DER\n");
        return -1;
    } else {
        printf("FINAL: Successful conversion to DER[%d]\n", len_final);
    }

    BIO *Cout = BIO_new(BIO_s_mem());
    PEM_write_bio_X509(Cout, cert);
    char* data;
    const long len = BIO_get_mem_data(Cout, &data);
    
    cc = X509_get_ext_count(cert);
    printf("Extension count in cert AFTER = %d\n", cc);
    printf("\ndata[%ld]: \n%s\n\n", len, data);
    BIO_free_all(Cout);



    int my_idx2 = X509_get_ext_by_NID(cert, NID_ct_precert_poison, -1);
    X509_EXTENSION* extPoison2 = X509_get_ext(cert, my_idx2);

    if(!extPoison2){
        printf("failed last extension[%d] extract \n ", my_idx2);
        return -1;
    } else {
        printf("Succeeded last extension extract[%d]\n ", my_idx2);
    }


    return 0;
}

此代码似乎可以工作,所有步骤都很好,问题是,当我将其保存到文件并运行命令时,显示的最终证书:

openssl x509 -in cert.pem -noout -text

它和原来的预认证一样,它包含毒扩展并且没有SCT。 即使比较两个文件,它们也是相同的。 我哪里做错了?

【问题讨论】:

    标签: c openssl x509


    【解决方案1】:

    您的主要问题是 X509 X509_CRL X509_REQ 当通过解析输入创建时 即不是从头开始构建的 OpenSSL 保存 tbs 编码并在输出时重用它和比较,这就是为什么您的 X509_cmp 失败)即使您更改了该编码中的某些字段,除非您签署更改,否则您必须这样做才能生成结果对象无论如何都有效。简而言之,您需要在进行更改后致电X509_sign() 或扩展形式X509_sign_ctx()。

    修复后你还有另一个问题:它确实删除了毒分机并添加了一个包含垃圾的 SCT 分机,因为你对d2i_SCT_LIST 的不必要调用改变了你使用的指针。删除它,加上你其他不需要的东西,会生成以下代码(使用我自己的预证书和密钥)来生成看起来正确的证书,当然你提供的 SCT 对它无效:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <openssl/asn1.h>
    #include <openssl/ct.h>
    #include <openssl/pem.h>
    #include <openssl/x509.h>
    
    int main(int argc, char **argv) {
        // size_t lenCert = 0, lenCert2 = 0;
        // char *filePEM  = "testpem/precert3.cert.pem";
        // replace mystery routines by one PEM:
        FILE *infile = fopen(argv[1],"r"); if(!infile) exit(1);
        X509 *cert = PEM_read_X509 (infile, NULL, NULL, NULL);
        fclose(infile);
        X509 *certRef = X509_dup(cert);
    
        if(!cert || cert==NULL){ // redundant, and too late
            printf("Failed parsing\n");
            return -1;
        }
    
    #if 0 // useless
        unsigned char *buf_init = NULL;
        int len_init = i2d_X509(certRef, &buf_init);
    #endif
    
        //--printf("size certificate: %ld\n", lenCert);
        //--X509_EXTENSION *tmpext;
        const STACK_OF(X509_EXTENSION) *allExt = X509_get0_extensions(cert);
        const STACK_OF(X509_EXTENSION) *allExt2 = X509_get0_extensions(certRef);
        int my_idx = X509v3_get_ext_by_NID(allExt, NID_ct_precert_poison, -1);
        int idx = my_idx;
    #if 0
        int cc = X509_get_ext_count(cert);
        printf("Extension count in cert BEFORE = %d\n", cc);
    
        //--printf((allExt==NULL) ? "Extensions extraction FAILED\n" : "Extensions extraction SUCCESS\n");
    #endif
    
    #if 0 // useless 
        int counter = X509v3_get_ext_count(allExt);
        printf("Extension[%d] count BEFORE = %d\n", idx, counter);
    #endif
    
    #if 0
        do { 
            X509_EXTENSION * tmpext = X509v3_get_ext(allExt, idx);
    #endif
            X509v3_delete_ext(allExt, idx);
    #if 0
            X509_EXTENSION_free(tmpext);
            idx = X509v3_get_ext_by_NID(allExt, NID_ct_precert_poison, -1);
            printf("pass\n");
        } while (idx != -1);
        printf("Extension count AFTER = %d\n", X509v3_get_ext_count(allExt));
    #endif
    
    #if 0
        if(X509_cmp( cert, certRef)){
            printf("Certificate modified\n\n");
        } else {
            printf("CENSORED \n");
        }
        printf("Extension count in cert AFTER = %d\n", X509_get_ext_count(cert));
    #endif
    
    #if 0 // useless
        unsigned char *buf_inter = NULL;
        int len_inter = i2d_X509(cert, &buf_inter);
    #endif
    
        unsigned char *dersct;
        size_t lenSCTList = 0;
        char *b64SCTList = "BIF6AHgAdgCwzIPlpfl9a698CcwoSQSHKsfoixMsY1C3xv0m4WxsdwAAAWZ7z/DQAAAEAwBHMEUCIQDKJPPQhWqje1rQq+T06x0iNlLT7rX71k23VPZkhm/QCwIgfhwNK7izeq0fHAlu7HuYRjmvym51RRdlNWhd50LQdu4=";
        // replace mystery routine
        dersct = malloc(strlen(b64SCTList)); // more than needed but convenient
        lenSCTList = EVP_DecodeBlock(dersct, (unsigned char*)b64SCTList, strlen(b64SCTList));
        printf("size final SCT List: %ld\n", lenSCTList);
    
    #if 0 // useless and harmful
        STACK_OF(SCT) * scts = d2i_SCT_LIST(NULL, (const unsigned char **) &dersct, lenSCTList);
        if(scts==NULL){
            printf("Could not convert SCT List!");
            return -1;
        } 
        printf("SCT List converted !\n");
    #endif
        ASN1_OCTET_STRING   *val   = ASN1_OCTET_STRING_new();
        ASN1_OCTET_STRING_set(val, dersct, (int)lenSCTList);
        free(dersct); // added
        X509_EXTENSION* extSCT = X509_EXTENSION_create_by_NID(NULL, NID_ct_precert_scts, 0, val);
    
    #if 0
        if(extSCT){
            printf("created extension\n");
        } else {
            printf("Failed to create extension\n");
            return -1;
        }
    #endif
    
        if( X509_add_ext(cert, extSCT, -1)) {
            printf("Extension added\n");
           //  X509_EXTENSION_free(extSCT);
    
        } else {
            printf("failed to add extension\n");
            return -1;
        }
    #if 0 // useless
        unsigned char *buf_final = NULL;
        int len_final = i2d_X509(cert, &buf_final);
    #endif
    
        // added
        FILE * keyfile = fopen(argv[2],"r"); if(!keyfile) exit(2);
        EVP_PKEY * signkey = PEM_read_PrivateKey (keyfile, NULL, NULL, NULL);
        fclose(keyfile);
        if( X509_sign(cert,signkey,EVP_sha256())<=0 ) exit(9);
    
        BIO *Cout = BIO_new(BIO_s_mem());
        PEM_write_bio_X509(Cout, cert);
        char* data;
        const long len = BIO_get_mem_data(Cout, &data);
        
        printf("Extension count in cert AFTER = %d\n", X509_get_ext_count(cert));
        printf("\ndata[%ld]: \n%s\n\n", len, data);
        // added
        FILE *outfile = fopen(argv[3],"w"); if(!outfile) exit(3);
        fwrite(data,1,len,outfile); fclose(outfile);
        BIO_free_all(Cout);
    
    #if 0 // useless
        int my_idx2 = X509_get_ext_by_NID(cert, NID_ct_precert_poison, -1);
        X509_EXTENSION* extPoison2 = X509_get_ext(cert, my_idx2);
    
        if(!extPoison2){
            printf("failed last extension[%d] extract \n ", my_idx2);
            return -1;
        } else {
            printf("Succeeded last extension extract[%d]\n ", my_idx2);
        }
    #endif
    
        return 0;
    }
    

    但是,修改get0 返回的值——并“丢弃”上面的const——不是很好的风格,可能在未来的某些实施中失败。直接在cert 上使用X509_get_ext_by_NID 和X509_delete_ext 会更安全,也更简单。

    【讨论】:

    • 感谢您的回答。我会尽快尝试。我不想对结果进行签名,因为我应该将其发送到 php 中的另一个服务来进行签名。那么是不是无法获取修改后的 tbs 并通过队列或套接字发送呢?
    • 如果该“服务”可以通过 OpenSSL 1.xx 中的 ENGINE 访问,您编写或从编写它的人那里获得(如果该服务本身很流行或使用像PKCS11这样流行的接口),您可以按照设计使用OpenSSL。 (3.xx 弃用了 ENGINE 以支持新架构。)否则,您要么必须深入研究内部结构,这可能随时中断,要么正如我所指出的,不要使用读入对象,而是创建一个 通过复制每个字段和扩展名从头开始新的对象(可能在此过程中跳过您不想要的那个)
    猜你喜欢
    • 2016-06-07
    • 2014-06-08
    • 2012-07-16
    • 2014-03-21
    • 2017-01-17
    • 1970-01-01
    • 2012-04-18
    • 1970-01-01
    • 2016-04-10
    相关资源
    最近更新 更多