2012-03-17 13 views
6

Antecedentes:Cómo calcular la huella digital SHA-1 del certificado X.509 en C/C++/Objective-C?

Estoy escribiendo una utilidad de cliente que es capaz de conectarse a un servidor remoto usando SSL/TLS. El cliente usa OpenSSL para realizar las transacciones SSL/TLS y me gustaría permitir que los usuarios especifiquen CA Certs autorizados (en el caso de certificados autofirmados o configuraciones de CA privadas) utilizados para firmar el certificado del servidor. Planeo usar la huella dactilar del certificado, el nombre común y las fechas de validez para que el usuario pueda ver rápidamente los certs que usa el cliente para validar los servidores.

Pregunta:

¿Cómo se calcula el hash SHA1/huella digital de un certificado X509 almacenado dentro de un archivo PEM con C/C++/Objective-C?

Después de días de búsqueda y experimentación, encontré una solución y la publicaré como respuesta; sin embargo, doy la bienvenida a soluciones mejores o más correctas.

Respuesta

5

encontré a continuación para producir la salida idéntico al anteriormente :

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

que es un poco más corto en el objetivo C. Sin embargo, necesita las siguientes extensiones para NSData/NSString para obtener el formato cerca de Netscape, OSX o 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

Aquí hay una solución que encontré usando las bibliotecas OpenSSL. Estoy publicando la pregunta y la respuesta en el desbordamiento de la pila con la esperanza de que ahorre a otros el problema y el tiempo de resolverlo por sí mismos.

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

Aquí es la compilación y la salida del programa anterior:

$ 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 

Aquí es la salida de la utilidad 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 
Cuestiones relacionadas