You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于wolfSSL的DER转PEM批量转换函数段错误排查

DER转PEM时wolfSSL环境下的段错误排查

问题场景

在wolfSSL环境下实现DER到PEM的证书格式转换,使用以下C函数:

int convertDERtoPEM(const char* derFilePath, const char* pemFolderPath) {
    FILE* derFile = fopen(derFilePath, "rb");
    if (!derFile) {
        printf("Error opening DER file %s\n", derFilePath);
        return -1;
    }

    unsigned char* derData = NULL;
    fseek(derFile, 0, SEEK_END);
    long derSize = ftell(derFile);
    rewind(derFile);
    derData = (unsigned char*)malloc(derSize);

    if (!derData) {
        printf("Memory allocation error\n");
        fclose(derFile);
        return -1;
    }

    fread(derData, 1, derSize, derFile);
    fclose(derFile);
    WOLFSSL_X509* x509 = wolfSSL_X509_new();
    if (!x509) {
        printf("Error creating X509 structure\n");
        free(derData);
        return -1;
    }

    if (wolfSSL_d2i_X509(&x509, &derData, derSize) == NULL) {
        printf("Error converting DER to X509\n");
        free(derData);
        wolfSSL_X509_free(x509);
        return -1;
    }
    
    const char* baseName = basename(derFilePath);
    char pemFileName[256];
    snprintf(pemFileName, sizeof(pemFileName), "%s/C_%.*s.pem", pemFolderPath, (int)(strlen(baseName) - 4), baseName);
    FILE* pemFile = fopen(pemFileName, "wb");
    
    if (!pemFile) {
        printf("Error opening PEM file %s for writing\n", pemFileName);
        free(derData);
        wolfSSL_X509_free(x509);
        return -1;
    }

    if (wolfSSL_PEM_write_X509(pemFile, x509) == 0) {
        printf("Error writing PEM certificate to %s\n", pemFileName);
        fclose(pemFile);
        wolfSSL_X509_free(x509);
        free(derData);
        return -1;
    }
      
    fclose(pemFile);
    wolfSSL_X509_free(x509);
    free(derData);
    printf("Conversion complete. %s converted to PEM and saved as %s.\n", derFilePath, pemFileName);
    return 0;
}

问题现象

  1. 批量执行该函数时直接触发段错误,栈信息如下:
#0  0x00007ffff78a54c9 in arena_for_chunk (ptr=0x55555556317a)
    at ./malloc/arena.c:156
#1  arena_for_chunk (ptr=0x55555556317a) at ./malloc/arena.c:160
#2  __GI___libc_free (mem=<optimized out>) at ./malloc/malloc.c:3390
#3  0x0000555555555782 in convertDERtoPEM (
    derFilePath=0x7fffffffde90 "./der/rights.1688.com_1.der", 
    pemFolderPath=0x555555556121 "./pem_c") at DtoP.c:71
#4  0x00005555555558b2 in main () at DtoP.c:89
  1. 注释最后一行free(derData)后,可完成部分证书转换,但处理某特定证书报错后仍触发段错误:
Conversion complete. ./der/rights.1688.com_1.der converted to PEM and saved as ./pem_c/C_rights.1688.com_1.pem.
Conversion complete. ./der/alibaba-ipmarket.tmall.com_1.der converted to PEM and saved as ./pem_c/C_alibaba-ipmarket.tmall.com_1.pem.
Conversion complete. ./der/xinyong.1688.com_1.der converted to PEM and saved as ./pem_c/C_xinyong.1688.com_1.pem.
Conversion complete. ./der/movie.jd.com_1.der converted to PEM and saved as ./pem_c/C_movie.jd.com_1.pem.
Conversion complete. ./der/hao123-static.cdn.bcebos.com_1.der converted to PEM and saved as ./pem_c/C_hao123-static.cdn.bcebos.com_1.pem.
Error writing PEM certificate to ./pem_c/C_gys.1688.com_1.pem
segfault

问题原因

核心问题是**wolfSSL_d2i_X509函数会修改传入的derData指针**:
该函数的第二个参数是unsigned char **类型,它在解析DER数据的过程中会移动这个指针,使其指向剩余未解析的字节。这就导致原来的derData不再是malloc返回的起始地址,后续对这个被篡改的指针执行free操作时,会触发堆内存错误,直接导致段错误。

即使注释了最后一行的free(derData),当处理特定证书出现wolfSSL_PEM_write_X509失败时,错误分支里的free(derData)同样会操作被篡改后的指针,因此仍然会触发段错误。

解决方案

保存malloc返回的原始指针,调用wolfSSL_d2i_X509时使用临时指针,确保后续free操作的是合法的堆起始地址。修改后的函数如下:

int convertDERtoPEM(const char* derFilePath, const char* pemFolderPath) {
    FILE* derFile = fopen(derFilePath, "rb");
    if (!derFile) {
        printf("Error opening DER file %s\n", derFilePath);
        return -1;
    }

    unsigned char* derData = NULL;
    fseek(derFile, 0, SEEK_END);
    long derSize = ftell(derFile);
    // 增加ftell错误判断
    if (derSize == -1) {
        printf("Failed to get DER file size\n");
        fclose(derFile);
        return -1;
    }
    rewind(derFile);
    derData = (unsigned char*)malloc(derSize);

    if (!derData) {
        printf("Memory allocation error\n");
        fclose(derFile);
        return -1;
    }

    fread(derData, 1, derSize, derFile);
    fclose(derFile);
    WOLFSSL_X509* x509 = wolfSSL_X509_new();
    if (!x509) {
        printf("Error creating X509 structure\n");
        free(derData); // 这里derData还未被修改,安全
        return -1;
    }

    // 使用临时指针传递给wolfSSL_d2i_X509,保留原始derData指针
    unsigned char* tmpDer = derData;
    if (wolfSSL_d2i_X509(&x509, &tmpDer, derSize) == NULL) {
        printf("Error converting DER to X509\n");
        free(derData); // 原始指针,安全
        wolfSSL_X509_free(x509);
        return -1;
    }
    
    const char* baseName = basename(derFilePath);
    // 检查baseName有效性,避免空指针
    if (!baseName) {
        printf("Failed to get base filename\n");
        free(derData);
        wolfSSL_X509_free(x509);
        return -1;
    }
    // 检查文件名后缀长度,避免strlen(baseName)-4为负数
    if (strlen(baseName) < 4) {
        printf("Invalid DER filename format\n");
        free(derData);
        wolfSSL_X509_free(x509);
        return -1;
    }
    char pemFileName[256];
    snprintf(pemFileName, sizeof(pemFileName), "%s/C_%.*s.pem", pemFolderPath, (int)(strlen(baseName) - 4), baseName);
    FILE* pemFile = fopen(pemFileName, "wb");
    
    if (!pemFile) {
        printf("Error opening PEM file %s for writing\n", pemFileName);
        free(derData); // 原始指针,安全
        wolfSSL_X509_free(x509);
        return -1;
    }

    if (wolfSSL_PEM_write_X509(pemFile, x509) == 0) {
        printf("Error writing PEM certificate to %s\n", pemFileName);
        fclose(pemFile);
        wolfSSL_X509_free(x509);
        free(derData); // 原始指针,安全
        return -1;
    }
      
    fclose(pemFile);
    wolfSSL_X509_free(x509);
    free(derData); // 原始指针,安全
    printf("Conversion complete. %s converted to PEM and saved as %s.\n", derFilePath, pemFileName);
    return 0;
}

额外注意事项

  • 增加ftell错误判断:避免ftell失败返回-1L后,malloc(-1L)触发非法内存分配。
  • 校验basename返回值:防止输入路径格式异常导致空指针访问。
  • 检查文件名后缀长度:避免strlen(baseName)-4出现负数,导致snprintf行为异常。

内容的提问来源于stack exchange,提问作者独揽双乔

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 05:55:55