1 /* netssl.c - Interface to OpenSSL for upsd
4 2002 Russell Kroll <rkroll@exploits.org>
5 2008 Arjen de Korte <adkorte-guest@alioth.debian.org>
7 based on the original implementation:
9 Copyright (C) 2002 Technorama Ltd. <oss-list-ups@technorama.net>
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include <sys/types.h>
27 #include <netinet/in.h>
28 #include <sys/socket.h>
37 #include <private/pprio.h>
44 char *certfile
= NULL
;
45 char *certname
= NULL
;
46 char *certpasswd
= NULL
;
48 #ifdef WITH_CLIENT_CERTIFICATE_VALIDATION
50 #endif /* WITH_CLIENT_CERTIFICATE_VALIDATION */
52 static int ssl_initialized
= 0;
56 /* stubs for non-ssl compiles */
57 void net_starttls(nut_ctype_t
*client
, int numarg
, const char **arg
)
59 send_err(client
, NUT_ERR_FEATURE_NOT_SUPPORTED
);
63 int ssl_write(nut_ctype_t
*client
, const char *buf
, size_t buflen
)
65 upslogx(LOG_ERR
, "ssl_write called but SSL wasn't compiled in");
69 int ssl_read(nut_ctype_t
*client
, char *buf
, size_t buflen
)
71 upslogx(LOG_ERR
, "ssl_read called but SSL wasn't compiled in");
77 ssl_initialized
= 0; /* keep gcc quiet */
80 void ssl_finish(nut_ctype_t
*client
)
83 upslogx(LOG_ERR
, "ssl_finish found active SSL connection but SSL wasn't compiled in");
87 void ssl_cleanup(void)
95 static SSL_CTX
*ssl_ctx
= NULL
;
97 static void ssl_debug(void)
100 char errmsg
[SMALLBUF
];
102 while ((e
= ERR_get_error()) != 0) {
103 ERR_error_string_n(e
, errmsg
, sizeof(errmsg
));
104 upsdebugx(1, "ssl_debug: %s", errmsg
);
108 static int ssl_error(SSL
*ssl
, int ret
)
112 e
= SSL_get_error(ssl
, ret
);
116 case SSL_ERROR_WANT_READ
:
117 upsdebugx(1, "ssl_error() ret=%d SSL_ERROR_WANT_READ", ret
);
120 case SSL_ERROR_WANT_WRITE
:
121 upsdebugx(1, "ssl_error() ret=%d SSL_ERROR_WANT_WRITE", ret
);
124 case SSL_ERROR_SYSCALL
:
125 if (ret
== 0 && ERR_peek_error() == 0) {
126 upsdebugx(1, "ssl_error() EOF from client");
128 upsdebugx(1, "ssl_error() ret=%d SSL_ERROR_SYSCALL", ret
);
133 upsdebugx(1, "ssl_error() ret=%d SSL_ERROR %d", ret
, e
);
140 #elif defined(WITH_NSS) /* WITH_OPENSSL */
142 static CERTCertificate
*cert
;
143 static SECKEYPrivateKey
*privKey
;
145 static char *nss_password_callback(PK11SlotInfo
*slot
, PRBool retry
,
149 /* Force not inted to retrieve password many times. */
152 upslogx(LOG_INFO
, "Intend to retrieve password for %s / %s: password %sconfigured",
153 PK11_GetSlotName(slot
), PK11_GetTokenName(slot
), certpasswd
?"":"not ");
154 return certpasswd
? PL_strdup(certpasswd
) : NULL
;
157 static void nss_error(const char* text
)
159 char buffer
[SMALLBUF
];
160 PRInt32 length
= PR_GetErrorText(buffer
);
161 if (length
> 0 && length
< SMALLBUF
) {
162 upsdebugx(1, "nss_error %ld in %s : %s", (long)PR_GetError(), text
, buffer
);
164 upsdebugx(1, "nss_error %ld in %s", (long)PR_GetError(), text
);
168 static int ssl_error(PRFileDesc
*ssl
, int ret
)
175 length
= PR_GetErrorText(buffer
);
176 if (length
> 0 && length
< 256) {
177 upsdebugx(1, "ssl_error() ret=%d %*s", e
, length
, buffer
);
179 upsdebugx(1, "ssl_error() ret=%d", e
);
185 static SECStatus
AuthCertificate(CERTCertDBHandle
*arg
, PRFileDesc
*fd
,
186 PRBool checksig
, PRBool isServer
)
188 nut_ctype_t
*client
= (nut_ctype_t
*)SSL_RevealPinArg(fd
);
189 SECStatus status
= SSL_AuthCertificate(arg
, fd
, checksig
, isServer
);
190 upslogx(LOG_INFO
, "Intend to authenticate client %s : %s.",
191 client
?client
->addr
:"(unnamed)",
192 status
==SECSuccess
?"SUCCESS":"FAILED");
196 static SECStatus
BadCertHandler(nut_ctype_t
*arg
, PRFileDesc
*fd
)
198 upslogx(LOG_WARNING
, "Certificate validation failed for %s",
199 (arg
&&arg
->addr
)?arg
->addr
:"<unnamed>");
200 #ifdef WITH_CLIENT_CERTIFICATE_VALIDATION
201 /* BadCertHandler is called when the NSS certificate validation is failed.
202 * If the certificate verification (user conf) is mandatory, reject authentication
205 return certrequest
==NETSSL_CERTREQ_REQUIRE
?SECFailure
:SECSuccess
;
206 #else /* WITH_CLIENT_CERTIFICATE_VALIDATION */
207 /* Always accept clients. */
209 #endif /* WITH_CLIENT_CERTIFICATE_VALIDATION */
212 static void HandshakeCallback(PRFileDesc
*fd
, nut_ctype_t
*client_data
)
214 upslogx(LOG_INFO
, "SSL handshake done successfully with client %s",
219 #endif /* WITH_OPENSSL | WITH_NSS */
221 void net_starttls(nut_ctype_t
*client
, int numarg
, const char **arg
)
225 #elif defined(WITH_NSS) /* WITH_OPENSSL */
228 #endif /* WITH_OPENSSL | WITH_NSS */
231 send_err(client
, NUT_ERR_ALREADY_SSL_MODE
);
235 client
->ssl_connected
= 0;
237 if ((!certfile
) || (!ssl_initialized
)) {
238 send_err(client
, NUT_ERR_FEATURE_NOT_CONFIGURED
);
244 #elif defined(WITH_NSS) /* WITH_OPENSSL */
245 if (!NSS_IsInitialized()) {
246 #endif /* WITH_OPENSSL | WITH_NSS */
247 send_err(client
, NUT_ERR_FEATURE_NOT_CONFIGURED
);
252 if (!sendback(client
, "OK STARTTLS\n")) {
258 client
->ssl
= SSL_new(ssl_ctx
);
261 upslog_with_errno(LOG_ERR
, "SSL_new failed\n");
266 if (SSL_set_fd(client
->ssl
, client
->sock_fd
) != 1) {
267 upslog_with_errno(LOG_ERR
, "SSL_set_fd failed\n");
272 ret
= SSL_accept(client
->ssl
);
276 client
->ssl_connected
= 1;
277 upsdebugx(3, "SSL connected");
281 upslog_with_errno(LOG_ERR
, "SSL_accept do not accept handshake.");
282 ssl_error(client
->ssl
, ret
);
285 upslog_with_errno(LOG_ERR
, "Unknown return value from SSL_accept");
286 ssl_error(client
->ssl
, ret
);
290 #elif defined(WITH_NSS) /* WITH_OPENSSL */
292 socket
= PR_ImportTCPSocket(client
->sock_fd
);
294 upslogx(LOG_ERR
, "Can not inialize SSL connection");
295 nss_error("net_starttls / PR_ImportTCPSocket");
299 client
->ssl
= SSL_ImportFD(NULL
, socket
);
300 if (client
->ssl
== NULL
){
301 upslogx(LOG_ERR
, "Can not inialize SSL connection");
302 nss_error("net_starttls / SSL_ImportFD");
306 if (SSL_SetPKCS11PinArg(client
->ssl
, client
) == -1){
307 upslogx(LOG_ERR
, "Can not inialize SSL connection");
308 nss_error("net_starttls / SSL_SetPKCS11PinArg");
312 /* Note cast to SSLAuthCertificate to prevent warning due to
313 * bad function prototype in NSS.
315 status
= SSL_AuthCertificateHook(client
->ssl
, (SSLAuthCertificate
)AuthCertificate
, CERT_GetDefaultCertDB());
316 if (status
!= SECSuccess
) {
317 upslogx(LOG_ERR
, "Can not inialize SSL connection");
318 nss_error("net_starttls / SSL_AuthCertificateHook");
322 status
= SSL_BadCertHook(client
->ssl
, (SSLBadCertHandler
)BadCertHandler
, client
);
323 if (status
!= SECSuccess
) {
324 upslogx(LOG_ERR
, "Can not inialize SSL connection");
325 nss_error("net_starttls / SSL_BadCertHook");
329 status
= SSL_HandshakeCallback(client
->ssl
, (SSLHandshakeCallback
)HandshakeCallback
, client
);
330 if (status
!= SECSuccess
) {
331 upslogx(LOG_ERR
, "Can not inialize SSL connection");
332 nss_error("net_starttls / SSL_HandshakeCallback");
336 status
= SSL_ConfigSecureServer(client
->ssl
, cert
, privKey
, NSS_FindCertKEAType(cert
));
337 if (status
!= SECSuccess
) {
338 upslogx(LOG_ERR
, "Can not inialize SSL connection");
339 nss_error("net_starttls / SSL_ConfigSecureServer");
343 status
= SSL_ResetHandshake(client
->ssl
, PR_TRUE
);
344 if (status
!= SECSuccess
) {
345 upslogx(LOG_ERR
, "Can not inialize SSL connection");
346 nss_error("net_starttls / SSL_ResetHandshake");
350 /* Note: this call can generate memory leaks not resolvable
351 * by any release function.
352 * Probably SSL session key object allocation. */
353 status
= SSL_ForceHandshake(client
->ssl
);
354 if (status
!= SECSuccess
) {
355 PRErrorCode code
= PR_GetError();
356 if (code
==SSL_ERROR_NO_CERTIFICATE
) {
357 upslogx(LOG_WARNING
, "Client %s do not provide certificate.",
360 nss_error("net_starttls / SSL_ForceHandshake");
361 /* TODO : Close the connection. */
365 client
->ssl_connected
= 1;
366 #endif /* WITH_OPENSSL | WITH_NSS */
373 #elif defined(WITH_OPENSSL)
374 #if OPENSSL_VERSION_NUMBER >= 0x10000000L
375 const SSL_METHOD
*ssl_method
;
377 SSL_METHOD
*ssl_method
;
379 #endif /* WITH_NSS|WITH_OPENSSL */
385 check_perms(certfile
);
389 SSL_load_error_strings();
392 if ((ssl_method
= TLSv1_server_method()) == NULL
) {
394 fatalx(EXIT_FAILURE
, "TLSv1_server_method failed");
397 if ((ssl_ctx
= SSL_CTX_new(ssl_method
)) == NULL
) {
399 fatalx(EXIT_FAILURE
, "SSL_CTX_new failed");
402 if (SSL_CTX_use_certificate_chain_file(ssl_ctx
, certfile
) != 1) {
404 fatalx(EXIT_FAILURE
, "SSL_CTX_use_certificate_chain_file(%s) failed", certfile
);
407 if (SSL_CTX_use_PrivateKey_file(ssl_ctx
, certfile
, SSL_FILETYPE_PEM
) != 1) {
409 fatalx(EXIT_FAILURE
, "SSL_CTX_use_PrivateKey_file(%s) failed", certfile
);
412 if (SSL_CTX_check_private_key(ssl_ctx
) != 1) {
414 fatalx(EXIT_FAILURE
, "SSL_CTX_check_private_key(%s) failed", certfile
);
417 if (SSL_CTX_set_cipher_list(ssl_ctx
, "HIGH:@STRENGTH") != 1) {
419 fatalx(EXIT_FAILURE
, "SSL_CTX_set_cipher_list failed");
422 SSL_CTX_set_verify(ssl_ctx
, SSL_VERIFY_NONE
, NULL
);
426 #elif defined(WITH_NSS) /* WITH_OPENSSL */
428 if (!certname
|| certname
[0]==0 ) {
429 upslogx(LOG_ERR
, "The SSL certificate name is not specified.");
433 PR_Init(PR_USER_THREAD
, PR_PRIORITY_NORMAL
, 0);
435 PK11_SetPasswordFunc(nss_password_callback
);
438 /* Note: this call can generate memory leaks not resolvable
439 * by any release function.
440 * Probably NSS key module object allocation and
441 * probably NSS key db object allocation too. */
442 status
= NSS_Init(certfile
);
444 status
= NSS_NoDB_Init(NULL
);
445 if (status
!= SECSuccess
) {
446 upslogx(LOG_ERR
, "Can not initialize SSL context");
447 nss_error("upscli_init / NSS_[NoDB]_Init");
451 status
= NSS_SetDomesticPolicy();
452 if (status
!= SECSuccess
) {
453 upslogx(LOG_ERR
, "Can not initialize SSL policy");
454 nss_error("upscli_init / NSS_SetDomesticPolicy");
458 /* Default server cache config */
459 status
= SSL_ConfigServerSessionIDCache(0, 0, 0, NULL
);
460 if (status
!= SECSuccess
) {
461 upslogx(LOG_ERR
, "Can not initialize SSL server cache");
462 nss_error("upscli_init / SSL_ConfigServerSessionIDCache");
466 status
= SSL_OptionSetDefault(SSL_ENABLE_SSL3
, PR_TRUE
);
467 if (status
!= SECSuccess
) {
468 upslogx(LOG_ERR
, "Can not enable SSLv3");
469 nss_error("upscli_init / SSL_OptionSetDefault(SSL_ENABLE_SSL3)");
472 status
= SSL_OptionSetDefault(SSL_ENABLE_TLS
, PR_TRUE
);
473 if (status
!= SECSuccess
) {
474 upslogx(LOG_ERR
, "Can not enable TLSv1");
475 nss_error("upscli_init / SSL_OptionSetDefault(SSL_ENABLE_TLS)");
479 #ifdef WITH_CLIENT_CERTIFICATE_VALIDATION
480 if (certrequest
< NETSSL_CERTREQ_NO
&&
481 certrequest
> NETSSL_CERTREQ_REQUEST
) {
482 upslogx(LOG_ERR
, "Invalid certificate requirement");
486 if (certrequest
== NETSSL_CERTREQ_REQUEST
||
487 certrequest
== NETSSL_CERTREQ_REQUIRE
) {
488 status
= SSL_OptionSetDefault(SSL_REQUEST_CERTIFICATE
, PR_TRUE
);
489 if (status
!= SECSuccess
) {
490 upslogx(LOG_ERR
, "Can not enable certificate request");
491 nss_error("upscli_init / SSL_OptionSetDefault(SSL_REQUEST_CERTIFICATE)");
496 if (certrequest
== NETSSL_CERTREQ_REQUIRE
) {
497 status
= SSL_OptionSetDefault(SSL_REQUIRE_CERTIFICATE
, PR_TRUE
);
498 if (status
!= SECSuccess
) {
499 upslogx(LOG_ERR
, "Can not enable certificate requirement");
500 nss_error("upscli_init / SSL_OptionSetDefault(SSL_REQUIRE_CERTIFICATE)");
504 #endif /* WITH_CLIENT_CERTIFICATE_VALIDATION */
506 cert
= PK11_FindCertFromNickname(certname
, NULL
);
508 upslogx(LOG_ERR
, "Can not find server certificate");
509 nss_error("upscli_init / PK11_FindCertFromNickname");
513 privKey
= PK11_FindKeyByAnyCert(cert
, NULL
);
515 upslogx(LOG_ERR
, "Can not find private key associate to server certificate");
516 nss_error("upscli_init / PK11_FindKeyByAnyCert");
521 #else /* WITH_OPENSSL | WITH_NSS */
522 upslogx(LOG_ERR
, "ssl_init called but SSL wasn't compiled in");
523 #endif /* WITH_OPENSSL | WITH_NSS */
526 int ssl_read(nut_ctype_t
*client
, char *buf
, size_t buflen
)
530 if (!client
->ssl_connected
) {
535 ret
= SSL_read(client
->ssl
, buf
, buflen
);
536 #elif defined(WITH_NSS) /* WITH_OPENSSL */
537 ret
= PR_Read(client
->ssl
, buf
, buflen
);
538 #endif /* WITH_OPENSSL | WITH_NSS */
541 ssl_error(client
->ssl
, ret
);
548 int ssl_write(nut_ctype_t
*client
, const char *buf
, size_t buflen
)
552 if (!client
->ssl_connected
) {
557 ret
= SSL_write(client
->ssl
, buf
, buflen
);
558 #elif defined(WITH_NSS) /* WITH_OPENSSL */
559 ret
= PR_Write(client
->ssl
, buf
, buflen
);
560 #endif /* WITH_OPENSSL | WITH_NSS */
562 upsdebugx(5, "ssl_write ret=%d", ret
);
567 void ssl_finish(nut_ctype_t
*client
)
571 SSL_free(client
->ssl
);
572 #elif defined(WITH_NSS)
573 PR_Shutdown(client
->ssl
, PR_SHUTDOWN_BOTH
);
574 PR_Close(client
->ssl
);
575 #endif /* WITH_OPENSSL | WITH_NSS */
576 client
->ssl_connected
= 0;
581 void ssl_cleanup(void)
585 SSL_CTX_free(ssl_ctx
);
588 #elif defined(WITH_NSS) /* WITH_OPENSSL */
589 CERT_DestroyCertificate(cert
);
590 SECKEY_DestroyPrivateKey(privKey
);
593 /* Called to release memory arena used by NSS/NSPR.
594 * Prevent to show all PL_ArenaAllocate mem alloc as leaks.
595 * https://developer.mozilla.org/en/NSS_Memory_allocation
598 #endif /* WITH_OPENSSL | WITH_NSS */
602 #endif /* WITH_SSL */