关于Openssl X509_Digest在Mbedtls上的实现

1 篇文章 0 订阅

      最近在研究VOIP, 需要用到基于mbedtls的TLS, 发现mbedtls很多API还真没有Openssl丰富, 官方也没有针对openssl的API做wrapper实现接口, 所以很多Openssl的API 功能, mbedtls居然没有, 或者说要自己写代码来实现, 这就有点曲线救国的味道了.

      如果没有使用过openssl或是mbedtls认证开发过产品, 对TLS这证书也是一知半解的话, 那初步看上去也是一头雾水, 不知道如何来替代实现X509_Digest功能, 所以要实现之前, 先看阅读源码openssl中关于X509_Digest的源码实现, 这部分源码涉及知识是X509证书的格式和解析,以及SHA1/SHA256算法实现, 其实算法可以不必深究, 我们需要实现的是API替代, SHA算法本身mbedtls就含有API. 证书格式相关部分可以自行查询资料了解, 本文不多做赘述.

      接下来我们先初步窥探下openssl源码中的X509_Digest实现原理, 按照官方文档就是DER数据做digest运算, 也就是SHA1/256运算完成计算一组值, 类似MD5这样的运算. 那原理明确了, 在mbedTLS实现就简单了. 

      根据OpenSSL的描述X509证书DER数据进行sha1运算, 那就分两部走: A 获得DER数据, B SHA运算.

      如何获得DER数据, 这个MBEDTLS有API可以载入mbedtls_x509_crt_parse/mbedtls_x509_crt_parse_file/mbedtls_x509_crt_parse_path 三个函数, 载入DER或是PEM数据格式的Cert文件, 完成对cert文件的解析和读取, 并存放在结构体变量:mbedtls_x509_crt 中.

      解析完成后的结构体mbedtls_x509_crt的变量A里面就可以找到DER的数据, 有了这个数据就可以结合SHA1/256算法完成Digest的实现.

      下面是实现的代码demo:

#include <string.h>
#include <stdio.h>

#include "mbedtls/x509_crt.h"
#include "mbedtls/sha1.h"
#include "mbedtls/sha512.h"
#include "mbedtls/sha256.h"

#define USAGE \
    "\n usage: digest param=<>...\n"                  \
    "\n acceptable parameters:\n"                       \
    "    ca_file=file       default: none\n"           \
    "    sha_method=method       default: sha1/256\n"           \
    "\n"

mbedtls_md_type_t digest_method[] = {
    MBEDTLS_MD_NONE,
    MBEDTLS_MD_MD2,       /**< The MD2 message digest. */
    MBEDTLS_MD_MD4,       /**< The MD4 message digest. */
    MBEDTLS_MD_MD5,       /**< The MD5 message digest. */
    MBEDTLS_MD_SHA1,      /**< The SHA-1 message digest. */
    MBEDTLS_MD_SHA224,    /**< The SHA-224 message digest. */
    MBEDTLS_MD_SHA256,    /**< The SHA-256 message digest. */
    MBEDTLS_MD_SHA384,    /**< The SHA-384 message digest. */
    MBEDTLS_MD_SHA512,    /**< The SHA-512 message digest. */
    MBEDTLS_MD_RIPEMD160, /**< The RIPEMD-160 message digest. */
};

int main(int argc, char** argv)
{
    int ret = -1;
    int i = 0;
    char *q=NULL, *p=NULL, *ca_file = NULL;
    unsigned char digest1[20]={0}, digest2[32]={0};
    unsigned char *p_result;
    size_t len = 0;
    int sha_method = 4;
    mbedtls_x509_crt cacert;

    mbedtls_x509_crt_init(&cacert);

    if( argc == 1 )
    {
usage:
        printf( USAGE );
        goto exit;
    }


    for( i = 1; i < argc; i++ )
    {
        p = argv[i];
        if( ( q = strchr( p, '=' ) ) == NULL )
            goto usage;
        *q++ = '\0';
	        
	if( strcmp( p, "ca_file" ) == 0 )
            ca_file = q;

	if( strcmp( p, "sha_method" ) == 0 ) {
	    sha_method = atoi( q );
	    if (sha_method < 0 || sha_method > 9)
                goto usage;
	}
    }

    if(strlen(ca_file))
    {
        if((ret = mbedtls_x509_crt_parse_file(&cacert, ca_file)) < 0 )
        {
            printf( " failed\n  !  mbedtls_x509_crt_parse_file returned -0x%x\n\n", -ret );
            goto exit;
        }

    }

    if (digest_method[sha_method] == MBEDTLS_MD_SHA1) {
        mbedtls_sha1_context sha1;
        mbedtls_sha1_init(&sha1);
        mbedtls_sha1_starts_ret(&sha1);
        mbedtls_sha1_update_ret(&sha1, cacert.raw.p, cacert.raw.len);
	mbedtls_sha1_finish_ret(&sha1, digest1);
	p_result = digest1;
	len = sizeof(digest1);
    } else if (digest_method[sha_method] == MBEDTLS_MD_SHA256) {
        mbedtls_sha256_context sha256;
        mbedtls_sha256_init(&sha256);
        mbedtls_sha256_starts_ret(&sha256, 0);
        mbedtls_sha256_update_ret(&sha256, cacert.raw.p, cacert.raw.len);
	mbedtls_sha256_finish_ret(&sha256, digest2);
	p_result = digest2;
	len = sizeof(digest2);
    }

    if (!p_result)
        goto exit;

    printf("Gigest %ld bytes: \n", len);

    for (int i = 0; i < len; i++) {
        printf("%.2X", p_result[i]);
	if (i < (len - 1))
	    printf(":");
    }

    printf("\n");

exit:
    mbedtls_x509_crt_free(&cacert);

    return ret;
}

  上面的代码实现了SHA1/SHA256的算法demo, 同时有打印信息输出digest结果, 注意编译需要安装对应mebdtls函数库和头文件.

   上述代码用GCC编译出可执行文件digest二进制. 代码中的caert->raw.p 存放的就是证书的原始DER数据

  下面是验证结果和对比实验.

   用Openssl工具创建一份自我签名的证书: cert.pem, 命令如下:

openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout key.pem -out cert.pem

  生成私钥匙pem: key.pem, 和证书公钥pem: cert.pem. 这两个文件都可以用cat cert.pem直接查看, 是ASCII字符的文件格式.

  创建证书时需要用户输入国家, 邮件, 公司名称等, 用户可以自己填写, 便于完成证书的生成.

  下面基于cert.pem 使用openssl生成SHA1和SHA256的对应输出digest结果:

$ openssl x509 -sha1 -in cert.pem --noout -fingerprint
SHA1 Fingerprint=F9:E4:5C:4A:38:29:5F:E3:2D:AA:76:20:4F:53:92:8A:5E:2F:01:E9

$ openssl x509 -sha256 -in cert.pem --noout -fingerprint
SHA256 Fingerprint=48:61:D0:39:62:FA:F8:92:9F:BE:49:EB:29:20:32:16:5B:62:80:05:61:CA:30:60:C7:22:CA:DF:66:5B:48:FC

 验证上述demo的代码基于mbedtls实现, 用编译出digest工具计算基于cert.pem的SHA1和SHA256值:

$ digest ca_file=./cert.pem sha_method=4
Gigest 20 bytes: 
F9:E4:5C:4A:38:29:5F:E3:2D:AA:76:20:4F:53:92:8A:5E:2F:01:E9
$ digest ca_file=./cert.pem sha_method=6
Gigest 32 bytes: 
48:61:D0:39:62:FA:F8:92:9F:BE:49:EB:29:20:32:16:5B:62:80:05:61:CA:30:60:C7:22:CA:DF:66:5B:48:FC

 上述指令, sha_method=4对应SHA1, sha_method=6对应SHA256, 可以看出计算结果和openssl工具完全相同.

  结论: 验证成功, 参考代码完全等效实现了OpenSSL的x509_digest逻辑.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值