2012-03-17 36 views
6

Bối cảnh:Cách tính dấu vân tay SHA-1 của chứng chỉ X.509 trong C/C++/Objective-C?

Tôi đang viết một tiện ích khách hàng có khả năng kết nối với máy chủ từ xa bằng SSL/TLS. Máy khách sử dụng OpenSSL để thực hiện các giao dịch SSL/TLS và tôi muốn cho phép người dùng chỉ định CA Certs được ủy quyền (trong trường hợp các chứng chỉ tự ký hoặc các thiết lập CA riêng) được sử dụng để ký chứng chỉ của máy chủ. Tôi có kế hoạch sử dụng dấu vân tay của cert, tên thông thường và ngày hiệu lực để cho phép người dùng xem nhanh các chứng chỉ mà máy khách sử dụng để xác thực các máy chủ.

Câu hỏi:

Làm thế nào để bạn tính toán SHA1 băm/vân tay của một cert X509 được lưu trữ trong một tập tin PEM sử dụng C/C++/Objective-C?

Sau ngày tìm kiếm và thử nghiệm tôi đã tìm thấy giải pháp và sẽ đăng câu trả lời, tuy nhiên tôi hoan nghênh các giải pháp tốt hơn hoặc chính xác hơn.

Trả lời

5

tôi thấy dưới đây để mang lại sản lượng giống trên :

+(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; 
} 

là một chút ngắn hơn trong mục tiêu C. Nó cần các phần mở rộng dưới đây để NSData/NSString mặc dù để có được định dạng gần Netscape, OSX hoặc 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]; 
} 
11

Đây là giải pháp tôi đã tìm thấy bằng cách sử dụng thư viện OpenSSL. Tôi đang đăng câu hỏi và câu trả lời trên tràn ngăn xếp với hy vọng rằng nó sẽ tiết kiệm cho người khác những rắc rối và thời gian của việc tìm ra nó.

#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(); 

    // 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); 
} 

Đây là biên dịch và đầu ra của chương trình trên:

$ 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 

Đây là kết quả từ các tiện ích 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 
Các vấn đề liên quan