ASN1_INTEGER 转换为 ASN1_STRING

9
我正在使用openssl获取有关x509证书的数据。 有没有一种方法将ASN1_INTEGER转换为ASN1_STRING,然后可以轻松地将其转换为char数组?有没有一种方法将其转换为任何其他可读格式?
编辑:我正在使用为iOS编译的openssl,因为我有iOS项目。这是我用来从证书中提取序列号的代码:
ASN1_INTEGER *serial = X509_get_serialNumber(certificateX509);
long value = ASN1_INTEGER_get(serial);
NSLog(@"Serial %ld", value);

certificateX509是一个有效的X509对象,我已经成功获取了一些其他字段(发行者名称、过期日期等)

编辑2:
最终我找到了一个解决方案,可能不是最简单的:

 ASN1_INTEGER *serial = X509_get_serialNumber(certificateX509);
 BIGNUM *bnser = ASN1_INTEGER_to_BN(serial, NULL);
 int n = BN_num_bytes(bnser);
 unsigned char outbuf[n];
 int bin = BN_bn2bin(bnser, outbuf);
 char *hexbuf = (char*) outbuf;

hexBuf现在包含需要读取为十六进制整数以检索逻辑值的字符。我使用NSMutableString创建可读性较强的字符串:

NSMutableString *str = [[NSMutableString alloc] init];
for (int i=0; i<n; i++) {
    NSString *temp = [NSString stringWithFormat:@"%.6x", hexbuf[i]];
    [str appendString:[NSString stringWithFormat:@"%@ ", temp]];
}

如果有更简单的方法,我真的很想知道。
5个回答

15

使用内置的BN_bn2hex(BIGNUM *)函数可以更简单地进行ASCII和十六进制转换。

ASN1_INTEGER *serial = X509_get_serialNumber(certificateX509);
BIGNUM *bnser = ASN1_INTEGER_to_BN(serial, NULL);
char *asciiHex = BN_bn2hex(bnser);

返回的 char* 在使用后应该被释放。 - Frizlab

6

可能的一种方法是,您可以将ASN1_INTEGER的值提取为普通的C整数:

#include <openssl/asn1.h>
#include <stdio.h>

int main(int argc, char** argv) {
  long value;
  ASN1_INTEGER asn1int = {0};

  ASN1_INTEGER_set(&asn1int, 42);
  value = ASN1_INTEGER_get(&asn1int);
  printf("The value is %ld.\n", value);

  return 0;
}

编译方法如下:

gcc -Wall -o sploots sploots.c -lcrypto

这会产生以下输出:

The value is 42.

要将值作为 char 数组中的字符串,请使用 snprintf
我怀疑还有可能使用 BIO 打印例程将该值转储到某种类型的 BIO(可能是内存 BIO)。但是,这种方法似乎更简单。
我得出这个答案的方式是查看 OpenSSL 头文件中的 ASN1_INTEGER。在寻找适合基于 BIO 的解决方案的 API 时,我注意到了 ASN1_INTEGER_get 函数。
在 OpenSSL 标头文件中查找通常是我学习如何使用 OpenSSL 的方式,因为该 API 的许多部分未记录或记录不正确或记录不完整。

不确定他在问什么,但对于证书序列号来说可能没有太大用处。例如,我检查了一个证书,序列号是“3c 08 cf ee be 9f eb c4 2b b1 3e e0 3d 62 0b df”。虽然确实没有其他方法,只能打开头文件并挖掘信息。 - Omri Barel
你说得对,这对我不起作用。我总是得到一个长整型值为-1。 - Maggie
听起来你无法从证书中获取ASN1_INTEGER。也许是一个BIGNUM?你能否在问题中添加提取它的代码? - Jean-Paul Calderone

2

我终于想出了一个解决方案,可能不是最直接的方法:

 ASN1_INTEGER *serial = X509_get_serialNumber(certificateX509);
 BIGNUM *bnser = ASN1_INTEGER_to_BN(serial, NULL);
 int n = BN_num_bytes(bnser);
 unsigned char outbuf[n];
 int bin = BN_bn2bin(bnser, outbuf);
 char *hexBuf = (char*) outbuf;

hexBuf包含需要读取为十六进制整数以检索逻辑值的字符。我使用NSMutableString创建可读字符串:

 NSMutableString *str = [[NSMutableString alloc] init];
    for (int i=0; i<n; i++) {
    NSString *temp = [NSString stringWithFormat:@"%.6x", hexbuf[i]];
    [str appendString:[NSString stringWithFormat:@"%@ ", temp]];
}

1
如果您只需要一个可读的NSString,那么“BN_bn2dec”比“BN_bn2hex”或“BN_bn2bin”更加简洁。不需要处理十六进制编码。 以下是我在iOS / ObjC中使用“pod 'OpenSSL-Universal','1.0.2.10'” 的方法:
ASN1_INTEGER *serialAsn1 = X509_get_serialNumber(certX509);
BIGNUM *serialBigNumber = ASN1_INTEGER_to_BN(serialAsn1, NULL);
char *serialChar = BN_bn2dec(serialBigNumber);

NSString *serialString = [NSString stringWithCString:(const char *) serialChar
                                            encoding:NSUTF8StringEncoding];

干杯。


1

这个方法对我有效,可以获取十六进制的序列号:

 ASN1_INTEGER* serial = X509_get_serialNumber(X509_certificate_ptr);
    BIGNUM* bn = ASN1_INTEGER_to_BN(serial, NULL);
    if (!bn) {
        // log here "Unable to convert ASN1INTEGER to BN";
        return "";
    }

    char* hex = BN_bn2hex(bn);
    if (!hex) {
        // Log here "Unable to convert BN to hex string";
        return "";
    }

    cout << hex; // this is your serial number. Can be converted using std::to_string()

    BN_free(bn);
    ASN1_INTEGER_free(serial);
    OPENSSL_free(hex);
    return serial_number;

没有错误检查和内存管理的代码基本上是这样的:
ASN1_INTEGER* serial = X509_get_serialNumber(X509_certificate_ptr);
BIGNUM* bn = ASN1_INTEGER_to_BN(serial, NULL);
char* hex = BN_bn2hex(bn);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接