如何在C/C ++/Objective-C中计算X.509证书的SHA-1指纹?[英] How to calculate X.509 certificate's SHA-1 fingerprint in C/C++/Objective-C?

本文是小编为大家收集整理的关于如何在C/C ++/Objective-C中计算X.509证书的SHA-1指纹?的处理方法,想解了如何在C/C ++/Objective-C中计算X.509证书的SHA-1指纹?的问题怎么解决?如何在C/C ++/Objective-C中计算X.509证书的SHA-1指纹?问题的解决办法?那么可以参考本文帮助大家快速定位并解决问题。

问题描述

背景:

我正在编写一个客户实用程序,该实用程序能够使用SSL/TLS连接到远程服务器.客户端使用OpenSSL执行SSL/TLS交易,我想允许用户指定用于签署服务器证书的授权CA Cert(如果是自签名证书或私人CA设置).我计划使用证书的指纹,通用名称和有效性日期,以允许用户快速查看客户端用于验证服务器的证书.

问题:

如何使用C/C ++/Objective-C?

计算存储在PEM文件中的X509证书的SHA1哈希/指纹.

经过几天的搜索和实验,我找到了一个解决方案,并将其作为答案,但是我欢迎更好或更正确的解决方案.

推荐答案

i在下面发现以产生与上述相同的输出:

+(NSData *)sha1:(SecCertificateRef) cert {
    // fingerprint is over canonical DER rep.
    CFDataRef data = SecCertificateCopyData(cert);
    NSData * out = [[NSData dataWithBytes:CFDataGetBytePtr(data) length:CFDataGetLength(data)] sha1Digest];
    CFRelease(data);
    return out;
}

在目标C中有点短一点.它需要以下扩展到NSDATA/NSSTRING,以使格式接近Netscape,OSX或Windows.

- (NSData *)md5Digest
{
    unsigned char result[CC_MD5_DIGEST_LENGTH];

    CC_MD5([self bytes], (CC_LONG)[self length], result);
    return [NSData dataWithBytes:result length:CC_MD5_DIGEST_LENGTH];
}

- (NSData *)sha1Digest
{
    unsigned char result[CC_SHA1_DIGEST_LENGTH];

    CC_SHA1([self bytes], (CC_LONG)[self length], result);
    return [NSData dataWithBytes:result length:CC_SHA1_DIGEST_LENGTH];
}

- (NSString *)hexStringValue
{
    NSMutableString *stringBuffer = [NSMutableString stringWithCapacity:([self length] * 2)];

    const unsigned char *dataBuffer = [self bytes];
    int i;

    for (i = 0; i < [self length]; ++i)
    {
        [stringBuffer appendFormat:@"%02lx", (unsigned long)dataBuffer[i]];
    }

    return [stringBuffer copy];
}


- (NSString *)hexColonSeperatedStringValue
{
    return [self hexColonSeperatedStringValueWithCapitals:YES];
}

- (NSString *)hexColonSeperatedStringValueWithCapitals:(BOOL)capitalize {
    NSMutableString *stringBuffer = [NSMutableString stringWithCapacity:([self length] * 3)];

    const unsigned char *dataBuffer = [self bytes];
    NSString * format = capitalize ? @"%02X" : @"%02x";
    int i;

    for (i = 0; i < [self length]; ++i)
    {
        if (i) 
            [stringBuffer appendString:@":"];
        [stringBuffer appendFormat:format, (unsigned long)dataBuffer[i]];
    }

    return [stringBuffer copy];
}

其他推荐答案

这是我使用OpenSSL库找到的解决方案.我在堆栈溢出上发布问题和答案,希望它能节省他人自己弄清楚的麻烦和时间.

#include <stdio.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/x509.h>
#include <openssl/bio.h>


int main(int argc, char * argv[])
{
   struct stat           sb;
   unsigned char       * buff;
   int                   fd;
   ssize_t               len;
   BIO                 * bio;
   X509                * x;
   unsigned              err;
   int                   pos;
   char                  errmsg[1024];
   const EVP_MD        * digest;
   unsigned char         md[EVP_MAX_MD_SIZE];
   unsigned int          n;

   // checks arguments
   if (argc != 2)
   {
      fprintf(stderr, "Usage: peminfo <pemfile>\n");
      return(1);
   };

   // checks file
   if ((stat(argv[1], &sb)) == -1)
   {
      perror("peminfo: stat()");
      return(1);
   };
   len = (sb.st_size * 2);

   // allocates memory
   if (!(buff = malloc(len)))
   {
      fprintf(stderr, "peminfo: out of virtual memory\n");
      return(1);
   };

   // opens file for reading
   if ((fd = open(argv[1], O_RDONLY)) == -1)
   {
      perror("peminfo: open()");
      free(buff);
      return(1);
   };

   // reads file
   if ((len = read(fd, buff, len)) == -1)
   {
      perror("peminfo: read()");
      free(buff);
      return(1);
   };

   // closes file
   close(fd);

   // initialize OpenSSL
   SSL_load_error_strings();
   SSL_library_init();
   OpenSSL_add_all_algorithms();

   // creates BIO buffer
   bio = BIO_new_mem_buf(buff, len);

   // decodes buffer
   if (!(x = PEM_read_bio_X509(bio, NULL, 0L, NULL)))
   {
      while((err = ERR_get_error()))
      {
         errmsg[1023] = '\0';
         ERR_error_string_n(err, errmsg, 1023);
         fprintf(stderr, "peminfo: %s\n", errmsg);
      };
      BIO_free(bio);
      free(buff);
      return(1);
   };

   // prints x509 info
   printf("name:      %s\n",    x->name);
   printf("serial:    ");
   printf("%02X", x->cert_info->serialNumber->data[0]);
   for(pos = 1; pos < x->cert_info->serialNumber->length; pos++)
      printf(":%02X", x->cert_info->serialNumber->data[pos]);
   printf("\n");

   // calculate & print fingerprint
   digest = EVP_get_digestbyname("sha1");
   X509_digest(x, digest, md, &n);
   printf("Fingerprint: ");
   for(pos = 0; pos < 19; pos++)
      printf("%02x:", md[pos]);
   printf("%02x\n", md[19]);

   // frees memory
   BIO_free(bio);
   free(buff);

   return(0);
}

这是上述程序的编译和输出:

$ cc -pedantic -W -Wall -Werror -O2  -Wno-deprecated -o peminfo  peminfo.c \
> -lcrypto -lssl
$ ./peminfo /usr/local/etc/openldap/keys/ca-certs.pem 
serial:      98:61:EB:C4:F2:C9:59:72
Fingerprint: 1d:59:d3:d4:4f:c9:e3:dc:f3:d7:66:b0:b8:7e:87:0b:01:73:c2:7e

这是OpenSSL实用程序的输出:

$ openssl x509 -noout -in /usr/local/etc/openldap/keys/ca-certs.pem \
> -fingerprint -serial
SHA1 Fingerprint=1D:59:D3:D4:4F:C9:E3:DC:F3:D7:66:B0:B8:7E:87:0B:01:73:C2:7E
serial=9861EBC4F2C95972

本文地址:https://www.itbaoku.cn/post/359340.html