How to calculate X.509 SHA-1 fingerprint certificate in C / C ++ / Objective-C?

Background:

I am writing a client utility that can connect to a remote server using SSL / TLS. The client uses OpenSSL to perform SSL / TLS transactions, and I would like to allow users to specify approved CA certificates (in the case of self-signed certificates or private CA installations) used to sign the server certificate. I plan to use the fingerprint, common name and validity dates of the certificate so that the user can quickly see the certificates that the client uses to verify the servers.

Question:

How do you calculate the SHA1 hash / fingerprint of an X509 certificate stored in a PEM file using C / C ++ / Objective-C?

After several days of searching and experimenting, I found a solution and will post it as an answer, however I welcome better or more correct solutions.

+6
source share
2 answers

I found below to get the identical output above:

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

which is slightly shorter in object C. It needs the following extensions for NSData / NSString, although in order to make formatting closer to Netscape, OSX or 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]; } 
+5
source

Here is a solution I found using OpenSSL libraries. I am posting a question and answer about stack overflows in the hope that this will save others from the need and time to figure it out ourselves.

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

Here is the compilation and output of the above program:

 $ 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 

Here is the output from the openssl utility:

 $ 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 
+11
source

Source: https://habr.com/ru/post/910980/


All Articles