int SslSocket::listen(const SocketAddress& sa, int backlog) const { //get certificate and key (is this the correct way?) std::string cName( (certname == "") ? "localhost.localdomain" : certname); CERTCertificate *cert = PK11_FindCertFromNickname(const_cast<char*>(cName.c_str()), 0); if (!cert) throw Exception(QPID_MSG("Failed to load certificate '" << cName << "'")); SECKEYPrivateKey *key = PK11_FindKeyByAnyCert(cert, 0); if (!key) throw Exception(QPID_MSG("Failed to retrieve private key from certificate")); NSS_CHECK(SSL_ConfigSecureServer(prototype, cert, key, NSS_FindCertKEAType(cert))); SECKEY_DestroyPrivateKey(key); CERT_DestroyCertificate(cert); return BSDSocket::listen(sa, backlog); }
int SslSocket::listen(uint16_t port, int backlog, const std::string& certName, bool clientAuth) const { //configure prototype socket: prototype = SSL_ImportFD(0, PR_NewTCPSocket()); if (clientAuth) { NSS_CHECK(SSL_OptionSet(prototype, SSL_REQUEST_CERTIFICATE, PR_TRUE)); NSS_CHECK(SSL_OptionSet(prototype, SSL_REQUIRE_CERTIFICATE, PR_TRUE)); } //get certificate and key (is this the correct way?) CERTCertificate *cert = PK11_FindCertFromNickname(const_cast<char*>(certName.c_str()), 0); if (!cert) throw Exception(QPID_MSG("Failed to load certificate '" << certName << "'")); SECKEYPrivateKey *key = PK11_FindKeyByAnyCert(cert, 0); if (!key) throw Exception(QPID_MSG("Failed to retrieve private key from certificate")); NSS_CHECK(SSL_ConfigSecureServer(prototype, cert, key, NSS_FindCertKEAType(cert))); SECKEY_DestroyPrivateKey(key); CERT_DestroyCertificate(cert); //bind and listen const int& socket = impl->fd; int yes=1; QPID_POSIX_CHECK(setsockopt(socket,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(yes))); struct sockaddr_in name; name.sin_family = AF_INET; name.sin_port = htons(port); name.sin_addr.s_addr = 0; if (::bind(socket, (struct sockaddr*)&name, sizeof(name)) < 0) throw Exception(QPID_MSG("Can't bind to port " << port << ": " << strError(errno))); if (::listen(socket, backlog) < 0) throw Exception(QPID_MSG("Can't listen on port " << port << ": " << strError(errno))); socklen_t namelen = sizeof(name); if (::getsockname(socket, (struct sockaddr*)&name, &namelen) < 0) throw QPID_POSIX_ERROR(errno); return ntohs(name.sin_port); }
int __pmSecureServerInit(void) { const PRUint16 *cipher; SECStatus secsts; int pathSpecified; int sts = 0; PM_INIT_LOCKS(); PM_LOCK(secureserver_lock); /* Only attempt this once. */ if (secure_server.initialized) goto done; secure_server.initialized = 1; if (PR_Initialized() != PR_TRUE) PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); /* Configure optional (cmdline) password file in case DB locked */ PK11_SetPasswordFunc(certificate_database_password); /* * Configure location of the NSS database with a sane default. * For servers, we default to the shared (sql) system-wide database. * If command line db specified, pass it directly through - allowing * any old database format, at the users discretion. */ if (!secure_server.database_path[0]) { const char *path; pathSpecified = 0; path = serverdb(secure_server.database_path, MAXPATHLEN, "sql:"); /* this is the default case on some platforms, so no log spam */ if (access(path, R_OK|X_OK) < 0) { if (pmDebugOptions.context) pmNotifyErr(LOG_INFO, "Cannot access system security database: %s", secure_server.database_path); sts = -EOPNOTSUPP; /* not fatal - just no secure connections */ secure_server.init_failed = 1; goto done; } } else pathSpecified = 1; /* * pmproxy acts as both a client and server. Since the * server init path happens first, the db previously * got opened readonly. Instead try to open RW. * Fallback if there is an error. */ secsts = NSS_InitReadWrite(secure_server.database_path); if( secsts != SECSuccess ) secsts = NSS_Init(secure_server.database_path); if (secsts != SECSuccess && !pathSpecified) { /* fallback, older versions of NSS do not support sql: */ serverdb(secure_server.database_path, MAXPATHLEN, ""); secsts = NSS_Init(secure_server.database_path); } if (secsts != SECSuccess) { pmNotifyErr(LOG_ERR, "Cannot setup certificate DB (%s): %s", secure_server.database_path, pmErrStr(__pmSecureSocketsError(PR_GetError()))); sts = -EOPNOTSUPP; /* not fatal - just no secure connections */ secure_server.init_failed = 1; goto done; } /* Some NSS versions don't do this correctly in NSS_SetDomesticPolicy. */ for (cipher = SSL_GetImplementedCiphers(); *cipher != 0; ++cipher) SSL_CipherPolicySet(*cipher, SSL_ALLOWED); /* Configure SSL session cache for multi-process server, using defaults */ secsts = SSL_ConfigMPServerSIDCache(1, 0, 0, NULL); if (secsts != SECSuccess) { pmNotifyErr(LOG_ERR, "Unable to configure SSL session ID cache: %s", pmErrStr(__pmSecureSocketsError(PR_GetError()))); sts = -EOPNOTSUPP; /* not fatal - just no secure connections */ secure_server.init_failed = 1; goto done; } else { secure_server.ssl_session_cache_setup = 1; } /* * Iterate over any/all PCP Collector nickname certificates, * seeking one valid certificate. No-such-nickname is not an * error (not configured by admin at all) but anything else is. */ CERTCertList *certlist; CERTCertDBHandle *nssdb = CERT_GetDefaultCertDB(); CERTCertificate *dbcert = PK11_FindCertFromNickname(secure_server.cert_nickname, NULL); if (dbcert) { PRTime now = PR_Now(); SECItem *name = &dbcert->derSubject; CERTCertListNode *node; certlist = CERT_CreateSubjectCertList(NULL, nssdb, name, now, PR_FALSE); if (certlist) { for (node = CERT_LIST_HEAD(certlist); !CERT_LIST_END(node, certlist); node = CERT_LIST_NEXT (node)) { if (pmDebugOptions.context) __pmDumpCertificate(stderr, secure_server.cert_nickname, node->cert); if (!__pmValidCertificate(nssdb, node->cert, now)) continue; secure_server.certificate_verified = 1; break; } CERT_DestroyCertList(certlist); } if (secure_server.certificate_verified) { secure_server.certificate_KEA = NSS_FindCertKEAType(dbcert); secure_server.private_key = PK11_FindKeyByAnyCert(dbcert, NULL); if (!secure_server.private_key) { pmNotifyErr(LOG_ERR, "Unable to extract %s private key", secure_server.cert_nickname); CERT_DestroyCertificate(dbcert); secure_server.certificate_verified = 0; sts = -EOPNOTSUPP; /* not fatal - just no secure connections */ secure_server.init_failed = 1; goto done; } } else { pmNotifyErr(LOG_ERR, "Unable to find a valid %s", secure_server.cert_nickname); CERT_DestroyCertificate(dbcert); sts = -EOPNOTSUPP; /* not fatal - just no secure connections */ secure_server.init_failed = 1; goto done; } } if (! secure_server.certificate_verified) { if (pmDebugOptions.context) { pmNotifyErr(LOG_INFO, "No valid %s in security database: %s", secure_server.cert_nickname, secure_server.database_path); } sts = -EOPNOTSUPP; /* not fatal - just no secure connections */ secure_server.init_failed = 1; goto done; } secure_server.certificate = dbcert; secure_server.init_failed = 0; sts = 0; done: PM_UNLOCK(secureserver_lock); return sts; }
SECStatus SSL_ConfigSecureServerWithCertChain(PRFileDesc *fd, CERTCertificate *cert, const CERTCertificateList *certChainOpt, SECKEYPrivateKey *key, SSL3KEAType kea) { sslSocket *ss; SECKEYPublicKey *pubKey = NULL; ssl3KeyPair *keyPair = NULL; SECStatus rv = SECFailure; ss = ssl_FindSocket(fd); if (!ss) { return SECFailure; } /* Both key and cert must have a value or be NULL */ /* Passing a value of NULL will turn off key exchange algorithms that were * previously turned on */ if (!cert != !key) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } /* make sure the key exchange is recognized */ if ((kea >= kt_kea_size) || (kea < kt_null)) { PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); return SECFailure; } if (kea != NSS_FindCertKEAType(cert)) { PORT_SetError(SSL_ERROR_CERT_KEA_MISMATCH); return SECFailure; } if (cert) { /* get the size of the cert's public key, and remember it */ pubKey = CERT_ExtractPublicKey(cert); if (!pubKey) return SECFailure; } if (key) { SECKEYPrivateKey * keyCopy = NULL; CK_MECHANISM_TYPE keyMech = CKM_INVALID_MECHANISM; if (key->pkcs11Slot) { PK11SlotInfo * bestSlot; bestSlot = PK11_ReferenceSlot(key->pkcs11Slot); if (bestSlot) { keyCopy = PK11_CopyTokenPrivKeyToSessionPrivKey(bestSlot, key); PK11_FreeSlot(bestSlot); } } if (keyCopy == NULL) keyMech = PK11_MapSignKeyType(key->keyType); if (keyMech != CKM_INVALID_MECHANISM) { PK11SlotInfo * bestSlot; /* XXX Maybe should be bestSlotMultiple? */ bestSlot = PK11_GetBestSlot(keyMech, NULL /* wincx */); if (bestSlot) { keyCopy = PK11_CopyTokenPrivKeyToSessionPrivKey(bestSlot, key); PK11_FreeSlot(bestSlot); } } if (keyCopy == NULL) keyCopy = SECKEY_CopyPrivateKey(key); if (keyCopy == NULL) goto loser; keyPair = ssl3_NewKeyPair(keyCopy, pubKey); if (keyPair == NULL) { SECKEY_DestroyPrivateKey(keyCopy); goto loser; } pubKey = NULL; /* adopted by serverKeyPair */ } if (ssl_ConfigSecureServer(ss, cert, certChainOpt, keyPair, kea) == SECFailure) { goto loser; } /* Only do this once because it's global. */ if (PR_SUCCESS == PR_CallOnceWithArg(&setupServerCAListOnce, &serverCAListSetup, (void *)(ss->dbHandle))) { rv = SECSuccess; } loser: if (keyPair) { ssl3_FreeKeyPair(keyPair); } if (pubKey) { SECKEY_DestroyPublicKey(pubKey); pubKey = NULL; } return rv; }
SECStatus SSL_ConfigSecureServerWithCertChain(PRFileDesc *fd, CERTCertificate *cert, const CERTCertificateList *certChainOpt, SECKEYPrivateKey *key, SSL3KEAType kea) { sslSocket *ss; SECKEYPublicKey *pubKey = NULL; ssl3KeyPair *keyPair = NULL; SECStatus rv = SECFailure; ss = ssl_FindSocket(fd); if (!ss) { return SECFailure; } if (!cert != !key) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } if ((kea >= kt_kea_size) || (kea < kt_null)) { PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); return SECFailure; } if (kea != NSS_FindCertKEAType(cert)) { PORT_SetError(SSL_ERROR_CERT_KEA_MISMATCH); return SECFailure; } if (cert) { pubKey = CERT_ExtractPublicKey(cert); if (!pubKey) return SECFailure; } if (key) { SECKEYPrivateKey * keyCopy = NULL; CK_MECHANISM_TYPE keyMech = CKM_INVALID_MECHANISM; if (key->pkcs11Slot) { PK11SlotInfo * bestSlot; bestSlot = PK11_ReferenceSlot(key->pkcs11Slot); if (bestSlot) { keyCopy = PK11_CopyTokenPrivKeyToSessionPrivKey(bestSlot, key); PK11_FreeSlot(bestSlot); } } if (keyCopy == NULL) keyMech = PK11_MapSignKeyType(key->keyType); if (keyMech != CKM_INVALID_MECHANISM) { PK11SlotInfo * bestSlot; bestSlot = PK11_GetBestSlot(keyMech, NULL ); if (bestSlot) { keyCopy = PK11_CopyTokenPrivKeyToSessionPrivKey(bestSlot, key); PK11_FreeSlot(bestSlot); } } if (keyCopy == NULL) keyCopy = SECKEY_CopyPrivateKey(key); if (keyCopy == NULL) goto loser; keyPair = ssl3_NewKeyPair(keyCopy, pubKey); if (keyPair == NULL) { SECKEY_DestroyPrivateKey(keyCopy); goto loser; } pubKey = NULL; } if (ssl_ConfigSecureServer(ss, cert, certChainOpt, keyPair, kea) == SECFailure) { goto loser; } if (PR_SUCCESS == PR_CallOnceWithArg(&setupServerCAListOnce, &serverCAListSetup, (void *)(ss->dbHandle))) { rv = SECSuccess; } loser: if (keyPair) { ssl3_FreeKeyPair(keyPair); } if (pubKey) { SECKEY_DestroyPublicKey(pubKey); pubKey = NULL; } return rv; }
SECStatus ConfigSecureServerWithNamedCert(PRFileDesc *fd, const char *certName, /*optional*/ ScopedCERTCertificate *certOut, /*optional*/ SSLKEAType *keaOut) { ScopedCERTCertificate cert(PK11_FindCertFromNickname(certName, nullptr)); if (!cert) { PrintPRError("PK11_FindCertFromNickname failed"); return SECFailure; } // If an intermediate certificate issued the server certificate (rather than // directly by a trust anchor), we want to send it along in the handshake so // we don't encounter unknown issuer errors when that's not what we're // testing. UniqueCERTCertificateList certList; ScopedCERTCertificate issuerCert( CERT_FindCertByName(CERT_GetDefaultCertDB(), &cert->derIssuer)); // If we can't find the issuer cert, continue without it. if (issuerCert) { // Sadly, CERTCertificateList does not have a CERT_NewCertificateList // utility function, so we must create it ourselves. This consists // of creating an arena, allocating space for the CERTCertificateList, // and then transferring ownership of the arena to that list. ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); if (!arena) { PrintPRError("PORT_NewArena failed"); return SECFailure; } certList.reset(static_cast<CERTCertificateList*>( PORT_ArenaAlloc(arena.get(), sizeof(CERTCertificateList)))); if (!certList) { PrintPRError("PORT_ArenaAlloc failed"); return SECFailure; } certList->arena = arena.forget(); // We also have to manually copy the certificates we care about to the // list, because there aren't any utility functions for that either. certList->certs = reinterpret_cast<SECItem*>( PORT_ArenaAlloc(certList->arena, 2 * sizeof(SECItem))); if (SECITEM_CopyItem(certList->arena, certList->certs, &cert->derCert) != SECSuccess) { PrintPRError("SECITEM_CopyItem failed"); return SECFailure; } if (SECITEM_CopyItem(certList->arena, certList->certs + 1, &issuerCert->derCert) != SECSuccess) { PrintPRError("SECITEM_CopyItem failed"); return SECFailure; } certList->len = 2; } ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot()); UniqueSECKEYPrivateKey key( PK11_FindKeyByDERCert(slot.get(), cert.get(), nullptr)); if (!key) { PrintPRError("PK11_FindKeyByDERCert failed"); return SECFailure; } SSLKEAType certKEA = NSS_FindCertKEAType(cert); if (SSL_ConfigSecureServerWithCertChain(fd, cert.get(), certList.get(), key.get(), certKEA) != SECSuccess) { PrintPRError("SSL_ConfigSecureServer failed"); return SECFailure; } if (certOut) { *certOut = cert.forget(); } if (keaOut) { *keaOut = certKEA; } return SECSuccess; }
void OsTLSServerConnectionSocket::NSSInitSocket(PRFileDesc* pDescriptor, long timeoutInSecs, const char* szPassword) { PRFileDesc *tcpSocket = NULL; PRSocketOptionData socketOption; PRStatus prStatus; SECStatus secStatus; // PRIntn hostenum; // PRNetAddr addr; SSLKEAType certKEA; tcpSocket = pDescriptor; if (socketDescriptor > OS_INVALID_SOCKET_DESCRIPTOR) { mpCert = PK11_FindCertFromNickname((char*)mCertNickname.data(), (char*)mCertPassword.data()); if (mpCert == NULL) { mbInitializeFailed = true; goto TlsError; } unsigned char* szPwd = (unsigned char*) PR_Malloc(mCertPassword.length()+ 1); strncpy((char*)szPwd, mCertPassword.data(), mCertPassword.length()+1); mpPrivKey = PK11_FindKeyByAnyCert(mpCert, (char*)szPwd); if (mpPrivKey == NULL) { mbInitializeFailed = true; goto TlsError; } if (tcpSocket) { /* Make the socket blocking. */ socketOption.option = PR_SockOpt_Nonblocking; socketOption.value.non_blocking = PR_FALSE; prStatus = PR_SetSocketOption(tcpSocket, &socketOption); if (prStatus != PR_SUCCESS) { mbInitializeFailed = true; goto TlsError; } /* Import the socket into the SSL layer. */ mpPRfd = SSL_ImportFD(NULL, tcpSocket); if (!mpPRfd) { mbInitializeFailed = true; goto TlsError; } /* Set configuration options. */ secStatus = SSL_OptionSet(mpPRfd, SSL_SECURITY, PR_TRUE); if (secStatus != SECSuccess) { mbInitializeFailed = true; goto TlsError; } secStatus = SSL_OptionSet(mpPRfd, SSL_HANDSHAKE_AS_SERVER, PR_TRUE); if (secStatus != SECSuccess) { mbInitializeFailed = true; goto TlsError; } secStatus = SSL_AuthCertificateHook(mpPRfd, (SSLAuthCertificate)OsTLS::AuthCertificate, (void *)CERT_GetDefaultCertDB()); if (secStatus != SECSuccess) { mbInitializeFailed = true; goto TlsError; } secStatus = SSL_BadCertHook(mpPRfd, (SSLBadCertHandler)OsTLS::BadCertHandler, NULL); if (secStatus != SECSuccess) { mbInitializeFailed = true; goto TlsError; } secStatus = SSL_HandshakeCallback(mpPRfd, (SSLHandshakeCallback)OsTLS::HandshakeCallback, (void*)this); if (secStatus != SECSuccess) { mbInitializeFailed = true; goto TlsError; } secStatus = SSL_SetPKCS11PinArg(mpPRfd, (void*)szPassword); if (secStatus != SECSuccess) { mbInitializeFailed = true; goto TlsError; } certKEA = NSS_FindCertKEAType(mpCert); secStatus = SSL_ConfigSecureServer(mpPRfd, mpCert, mpPrivKey, certKEA); if (secStatus != SECSuccess) { mbInitializeFailed = true; goto TlsError; } secStatus = SSL_ResetHandshake(mpPRfd, /* asServer */ PR_TRUE); if (secStatus != SECSuccess) { mbInitializeFailed = true; goto TlsError; } PR_Free(szPwd); } else { mIsConnected = FALSE; OsConnectionSocket::close(); mbInitializeFailed = true; } } TlsError: return; }