问题描述
背景:
我正在编写一个客户实用程序,该实用程序能够使用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