2012-03-17 2 views
6

Fond:Comment calculer l'empreinte SHA-1 du certificat X.509 en C/C++/Objective-C?

J'écris un utilitaire client qui est capable de se connecter à un serveur distant en utilisant SSL/TLS. Le client utilise OpenSSL pour effectuer les transactions SSL/TLS et je voudrais autoriser les utilisateurs à spécifier des Certs CA autorisés (dans le cas des certificats auto-signés ou des configurations CA privées) utilisés pour signer le certificat du serveur. Je prévois d'utiliser l'empreinte, le nom commun et les dates de validité du certificat pour permettre à l'utilisateur d'afficher rapidement les certificats que le client utilise pour valider les serveurs.

Question:

Comment calculer le hachage SHA1/empreintes digitales d'un cert X509 stocké dans un fichier PEM en C/C++/Objective-C? Après des jours de recherche et d'expérimentation, j'ai trouvé une solution et je l'afficherai comme une réponse, mais j'apprécie les solutions meilleures ou plus correctes.

Répondre

5

je trouve ci-dessous pour obtenir une sortie identique ci-dessus :

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

qui est un peu plus court dans l'objectif C. Il a cependant besoin des extensions NSData/NSString ci-dessous pour obtenir le formatage proche de Netscape, OSX ou 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

Voici une solution que j'ai trouvée en utilisant les bibliothèques OpenSSL. Je poste la question et la réponse sur le débordement de la pile dans l'espoir que cela épargnera aux autres le problème et le temps de la comprendre eux-mêmes.

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

Voici la compilation et la sortie du programme ci-dessus:

$ 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 

Voici la sortie de l'utilitaire 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 
Questions connexes