2012-05-14 1 views
2

J'essaie d'obtenir le certificat ssl d'un serveur distant sous Windows. Une option que j'ai trouvée est d'utiliser openssl. La commande de le faire comme indiqué par certains postes sur le internet est:Obtention du certificat ssl sous Windows en utilisant C++

openssl.exe s_client -showcerts -connect {REMOTE_SERVER_IP}:{REMOTE_SERVER_PORT} 

Cela fonctionne parfaitement, mais mon problème est que la commande ci-dessus a un délai d'attente de 300 secondes. Le certificat lui-même est imprimé assez rapidement et je ne vois aucune raison d'attendre 300 secondes quand j'obtiens tout ce que je veux dans les premières secondes. Encore je pense qu'il n'y a aucun moyen de changer le paramètre timeout sur s_client. J'ai donc essayé de trouver un moyen de tuer un processus sur Windows après une période de temps donnée, mais encore une fois n'avait pas de chance là-bas. Des idées sur comment cela peut-il être fait? S'il existe d'autres moyens d'obtenir un certificat ssl de serveurs distants et de le stocker dans un fichier, cela fera également l'affaire.

EDIT: selon la demande de Bruno en ajoutant plus d'informations. J'essaie de créer une application C++ qui obtient le certificat SSL d'un serveur distant et le stocke dans un fichier pour un traitement ultérieur. Comme mon application utilise déjà openssl.exe, soit j'ai besoin d'une solution qui utilise openssl.exe ou une commande Windows standard (c'est-à-dire ne nécessite pas de bibliothèques supplémentaires).

EDIT2: J'ai trouvé un moyen d'éviter l'attente dans Linux - il suffit de créer un fichier vide et de rediriger l'entrée d'openssl s_client vers celui-ci (ou utiliser un tube pour passer l'entrée vide). Cela fonctionne aussi bien sur windows que sur les anciennes versions d'openssl (0.9.8l). Je l'ai essayé avec 0.9.8r et avec 1.0.1b et rediriger l'entrée vers un fichier vide n'aide pas là.

+0

Avez-vous essayé d'appuyer sur Ctrl + C ou Ctrl + D? – Bruno

+0

La commande est démarrée à partir d'un programme. Si je l'exécute à partir de la ligne de commande ctrl + c fait le travail mais ce n'est pas ce dont j'ai besoin. –

+0

Jusqu'à présent, cela ressemble à une question SuperUser (d'où les votes à fermer). Si vous l'exécutez à partir d'un programme, dites-nous comment (et quelle langue). – Bruno

Répondre

6

Voici un programme minimaliste que j'ai créé qui se connecte à un serveur et imprime son certificat ssl à la sortie standard. Espérons que cela aidera quelqu'un d'autre pour résoudre le problème similaire:

#ifdef WIN32 
#include <windows.h> 
#include <winsock2.h> 
#else 
#include <netinet/in.h> 
#include <netinet/tcp.h> 
#include <netdb.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#endif 

#include <openssl/ssl.h>  
#include <cstdlib> 
#include <iostream> 

static const char *host= "10.23.10.12"; 
static int port=443; 

int tcp_connect(const char *host,int port) 
{ 
#ifdef WIN32 
    WSADATA wsaData; 
    WORD version; 
    int error; 

    version = MAKEWORD(2, 0); 

    error = WSAStartup(version, &wsaData); 

    /* check for error */ 
    if (error != 0) 
    { 
     /* error occured */ 
     return -1; 
    } 

    /* check for correct version */ 
    if (LOBYTE(wsaData.wVersion) != 2 || 
     HIBYTE(wsaData.wVersion) != 0) 
    { 
     /* incorrect WinSock version */ 
     WSACleanup(); 
     return -1; 
    } 

    /* WinSock has been initialized */ 
#endif 

    struct hostent *hp; 
    struct sockaddr_in addr; 
    int sock; 

    if(!(hp=gethostbyname(host))) 
     printf("Couldn't resolve host"); 
    memset(&addr,0,sizeof(addr)); 
    addr.sin_addr=*(struct in_addr*) 
     hp->h_addr_list[0]; 
    addr.sin_family=AF_INET; 
    addr.sin_port=htons(port); 

    if((sock=(int)socket(AF_INET,SOCK_STREAM, 
        IPPROTO_TCP))<0) 
     printf("Couldn't create socket"); 
    if(connect(sock,(struct sockaddr *)&addr, 
       sizeof(addr))<0) 
     printf("Couldn't connect socket"); 

    return sock; 
} 

int main(int argc,char **argv) 
{ 
    SSL_CTX *ctx; 
    SSL *ssl; 
    BIO *sbio; 
    int sock; 

    SSL_METHOD *meth=NULL; 
    meth=SSLv23_client_method(); 
    OpenSSL_add_ssl_algorithms(); 
    SSL_load_error_strings(); 
    ctx=SSL_CTX_new(meth); 

    /* Connect the TCP socket*/ 
    sock=tcp_connect(host,port); 

    /* Connect the SSL socket */ 
    ssl=SSL_new(ctx); 
    sbio=BIO_new_socket(sock,BIO_NOCLOSE); 
    SSL_set_bio(ssl,sbio,sbio); 

    if(SSL_connect(ssl)<=0) 
    printf("SSL connect error"); 

    X509 *peer; 
    peer=SSL_get_peer_certificate(ssl); 
    PEM_write_X509(stdout, peer); 

    SSL_CTX_free(ctx); 

    close(sock); 
#ifdef WIN32 
    closesocket(sock); 
    WSACleanup(); 
#else 
    close(sock); 
#endif 
    exit(0); 
} 

Le code est version modifiée des exemples trouvés here comme suggéré par this post.

EDIT: J'ai continué à obtenir l'erreur OPENSSL_UPLINK: pas OPENSSL_APPLINK sur Windows. Après beaucoup de recherche autour de l'Internet et j'ai trouvé this post ajouté à mon code:

extern "C" { 
    #include <openssl/applink.c> 
} 

semble que ce soit un travail autour pour éviter l'exigence de compilateur et la gestion du temps la compatibilité des options.

+0

Puis-je utiliser le nom de domaine du site pour l'extraction de certificats? (pas l'adresse IP et le port) f.e. "http://google.com" au lieu de "10.23.10.12" port = 443 – BergP

+1

ce code devrait fonctionner correctement. Notez cet appel: 'gethostbyname (host)' il devrait essayer de résoudre le nom d'hôte. –

+0

puis-je obtenir "adresse IP" et "port" de struct hostent renvoyé par gethostbyname (hôte)? – BergP

Questions connexes