HSAdmin Backend Domains, E-Mail, Datenbanken
Purodha
2013-02-20 4a7e12928010374d76e677c8ec3ea4f5e63e9487
commit | author | age
c64ab5 1 /***************************************************************************
CD 2  *   Copyright (C) 2005 by Christof Donat   *
3  *   cdonat@gmx.de   *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) any later version.                                   *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19  ***************************************************************************/
20
21 #include "sslclient.h"
22 #include "logger.h"
23
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <netinet/in.h>
27 #include <arpa/inet.h>
28 #include <netdb.h>
29
30 #include <boost/filesystem/operations.hpp>
31 #include <boost/lexical_cast.hpp>
32
33 #include <gnutls/x509.h>
34
35 using std::string;
36 using std::streamsize;
37 using boost::lexical_cast;
38 using boost::bad_lexical_cast;
39
40 int SSLDevice::countInstances = 0;
41
42 SSLDevice::SSLDevice(const string& address, const short int port): m_session(0) {
43     this->init(address.c_str(),port);
44 }
45 SSLDevice::SSLDevice(const char* address, const short int port): m_session(0) {
46     this->init(address,port);
47 }
48
49 void SSLDevice::init(const char* address, const short int port) {
50         struct sockaddr_in addr;
51         bzero(&addr,sizeof(addr));
52         addr.sin_family = AF_INET;
53     if( (addr.sin_addr.s_addr = inet_addr(address)) == INADDR_NONE ) {
54         struct hostent* hp = gethostbyname(address);
55         if( hp == 0 ) throw("can't resolve hostname '"+string(address)+"'");
56         bcopy(hp->h_addr, (char*) &addr.sin_addr, hp->h_length);
57     }
58     addr.sin_port = htons(port);
59
60     if( (m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0 ) throw(string("can't open socket"));
61     if( ::connect(m_socket, (struct sockaddr*) &addr, sizeof(addr)) < 0 ) {
62         ::close(m_socket);
63         throw("can't connect to '"+string(address)+"' port "+(lexical_cast<string>(port)));
64     }
65
66     const int cert_type_priority[3] = { GNUTLS_CRT_X509, GNUTLS_CRT_OPENPGP, 0 };
67
68     m_session = new gnutls_session;
69
70     if( countInstances == 0 ) gnutls_global_init();
71     countInstances++;
72
73     gnutls_certificate_allocate_credentials(&m_xcred);
74     gnutls_certificate_set_x509_trust_file(m_xcred, "ca.pem", GNUTLS_X509_FMT_PEM);
75
76     gnutls_init(m_session,GNUTLS_CLIENT);
77
78     gnutls_set_default_priority(*m_session);
79
80     gnutls_credentials_set(*m_session, GNUTLS_CRD_CERTIFICATE, m_xcred);
81
82     gnutls_transport_set_ptr(*m_session, (gnutls_transport_ptr)&m_socket);
83
84     if( gnutls_handshake(*m_session) < 0 )
85         throw(string(gnutls_protocol_get_name(gnutls_protocol_get_version(*m_session)))+" Handshake failed");
86
87     verify_certificate( *m_session, address);
88 }
89 SSLDevice::SSLDevice(const SSLDevice& other) : m_session(other.m_session), m_socket(other.m_socket), m_xcred(other.m_xcred) { }
90 SSLDevice::~SSLDevice() { }
91
92 void SSLDevice::closeSocket() {
93     gnutls_bye(*m_session, GNUTLS_SHUT_RDWR);
94     gnutls_certificate_free_credentials(m_xcred);
95     ::close(m_socket);
96     gnutls_deinit(*m_session);
97     delete(m_session);
98
99     countInstances--;
100     if( countInstances == 0 ) gnutls_global_deinit();
101 }
102
103 streamsize SSLDevice::read(char* s, streamsize n) { return (streamsize)gnutls_record_recv(*m_session,(void*)s,(size_t)n); }
104 streamsize SSLDevice::write(const char* s, streamsize n) { 
105     /*streamsize i = (streamsize)gnutls_record_send(*m_session,(const void*)s,(size_t)n); 
106     Logger::log(Logger::DEBUG,string("sending ")+boost::lexical_cast<string>(i)+" von "+boost::lexical_cast<string>(n)+" bytes: \n---\n"+s+"\n---\n");*/
107     return (streamsize)gnutls_record_send(*m_session,(const void*)s,(size_t)n); //i;
108 }
109
110 void SSLDevice::verify_certificate( gnutls_session session, string hostname) {
111     boost::filesystem::path general("/etc/hsadminc.cert");
112     if( boost::filesystem::exists(general) && !boost::filesystem::is_directory(general) )
113         gnutls_certificate_set_x509_trust_file (m_xcred, general.native().c_str(), GNUTLS_X509_FMT_PEM);
114     //string privfilename = getenv("HOME");
115     string priv = getenv("HOME");
116     boost::filesystem::path p( priv + "/.hsadmin.cert" ); 
117     //p /= ".hsadminc.conf";
118
119     if( boost::filesystem::exists(p) && !boost::filesystem::is_directory(p) )
120         gnutls_certificate_set_x509_trust_file (m_xcred, p.native().c_str(), GNUTLS_X509_FMT_PEM);
121     //gnutls_certificate_set_x509_trust_file (m_xcred, const char * cafile, PEM)
122
123     unsigned int status = 0;//gnutls_certificate_verify_peers(*m_session);
124     /*if( gnutls_certificate_verify_peers2(*m_session, &status) < 0 )
125         throw(string("Error while verifying certificate"));*/
126
127     string tval = "Certificate Verification failed: ";
128     if( status & GNUTLS_CERT_INVALID )          { throw(tval+"The certificate is not trustet"); }
129     if( status & GNUTLS_CERT_SIGNER_NOT_FOUND ) { throw(tval+"The certificate has no known Issuer"); }
130     if( status & GNUTLS_CERT_REVOKED )          { throw(tval+"The certificate has been revoked"); }
131
132     // the further checks are only valid for X509 certificates
133     if ( gnutls_certificate_type_get(session) != GNUTLS_CRT_X509) return;
134
135     const gnutls_datum* cert_list;
136     unsigned int cert_list_size;
137     gnutls_x509_crt cert;
138
139     if ( gnutls_x509_crt_init(&cert) < 0) throw(tval+"error in initialization");
140
141     cert_list = gnutls_certificate_get_peers(session, &cert_list_size);
142     if ( cert_list == NULL )  throw(tval+"no certificate found");
143
144     bool failed = false;
145     string tReason = "";
146     for( int i = 0; i < cert_list_size-1; i++ ) {
147         bool failed = false;
148
149         if ( gnutls_x509_crt_import( cert, &cert_list[0], GNUTLS_X509_FMT_DER) < 0)
150             throw(tval+"error parsing certificate Number "+lexical_cast<string>(i));
151
152         if ( gnutls_x509_crt_get_expiration_time(cert) < time(0) ) {
153             tReason = "The certificate has expired";
154             failed = true;
155         }
156
157         if ( gnutls_x509_crt_get_activation_time(cert) > time(0) ) {
158             tReason = "The certificate is not yet activated";
159             failed = true;
160         }
161         if ( !gnutls_x509_crt_check_hostname(cert,hostname.c_str()) ) {
162             tReason = "The certificate’s owner does not match hostname ’";
163             tReason += hostname +"'";
164             failed = true;
165         }
166         gnutls_x509_crt_deinit(cert);
167
168         if( !failed ) break;
169     }
170     if( failed ) throw(tval+tReason);
171 }