std::shared_ptr<SSLContext> getSSLContext(folly::StringPiece pemCertPath, folly::StringPiece pemKeyPath, folly::StringPiece pemCaPath) { static constexpr std::chrono::minutes kSslReloadInterval{5}; thread_local std::unordered_map<CertPaths, ContextInfo, CertPathsHasher> localContexts; CertPaths paths; paths.pemCertPath = pemCertPath; paths.pemKeyPath = pemKeyPath; paths.pemCaPath = pemCaPath; auto iter = localContexts.find(paths); if (localContexts.find(paths) == localContexts.end()) { // Copy strings. ContextInfo info; info.pemCertPath = pemCertPath.toString(); info.pemKeyPath = pemKeyPath.toString(); info.pemCaPath = pemCaPath.toString(); // Point all StringPiece's to our own strings. paths.pemCertPath = info.pemCertPath; paths.pemKeyPath = info.pemKeyPath; paths.pemCaPath = info.pemCaPath; iter = localContexts.insert(std::make_pair(paths, std::move(info))).first; } auto& contextInfo = iter->second; auto now = std::chrono::steady_clock::now(); if (contextInfo.context == nullptr || now - contextInfo.lastLoadTime > kSslReloadInterval) { try { auto sslContext = std::make_shared<SSLContext>(); sslContext->loadCertificate(pemCertPath.begin()); sslContext->loadPrivateKey(pemKeyPath.begin()); sslContext->loadTrustedCertificates(pemCaPath.begin()); sslContext->loadClientCAList(pemCaPath.begin()); // Disable compression if possible to reduce CPU and memory usage. #ifdef SSL_OP_NO_COMPRESSION sslContext->setOptions(SSL_OP_NO_COMPRESSION); #endif contextInfo.lastLoadTime = now; contextInfo.context = std::move(sslContext); } catch (const apache::thrift::transport::TTransportException& ex) { LOG(ERROR) << "Failed to load certificate, ex: " << ex.what(); } } return contextInfo.context; }
int main(int argc, char** argv) { signal(SIGINT, stopHandler); /* catches ctrl-c */ #ifdef UA_ENABLE_MULTITHREADING pthread_rwlock_init(&writeLock, 0); #endif UA_ServerNetworkLayer nl = UA_ServerNetworkLayerTCP(UA_ConnectionConfig_standard, 16664); UA_ServerConfig config = UA_ServerConfig_standard; config.serverCertificate = loadCertificate(); config.networkLayers = &nl; config.networkLayersSize = 1; UA_Server *server = UA_Server_new(config); // add node with the datetime data source UA_DataSource dateDataSource = (UA_DataSource) {.handle = NULL, .read = readTimeData, .write = NULL}; UA_VariableAttributes v_attr; UA_VariableAttributes_init(&v_attr); v_attr.description = UA_LOCALIZEDTEXT("en_US","current time"); v_attr.displayName = UA_LOCALIZEDTEXT("en_US","current time"); v_attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE; const UA_QualifiedName dateName = UA_QUALIFIEDNAME(1, "current time"); UA_NodeId dataSourceId; UA_Server_addDataSourceVariableNode(server, UA_NODEID_NULL, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), dateName, UA_NODEID_NULL, v_attr, dateDataSource, &dataSourceId); #ifndef _WIN32 /* cpu temperature monitoring for linux machines */ const char *temperatureFileName = "/sys/class/thermal/thermal_zone0/temp"; // RaspberryPi // const char *temperatureFileName = "/sys/class/hwmon/hwmon0/device/temp1_input"; // Beaglebone // const char *temperatureFileName = "/sys/class/thermal/thermal_zone3/temp"; // Intel Edison Alternative 1 // const char *temperatureFileName = "/sys/class/thermal/thermal_zone4/temp"; // Intel Edison Alternative 2 if((temperatureFile = fopen(temperatureFileName, "r"))) { // add node with the data source UA_DataSource temperatureDataSource = (UA_DataSource) { .handle = NULL, .read = readTemperature, .write = NULL}; const UA_QualifiedName tempName = UA_QUALIFIEDNAME(1, "cpu temperature"); UA_VariableAttributes_init(&v_attr); v_attr.description = UA_LOCALIZEDTEXT("en_US","temperature"); v_attr.displayName = UA_LOCALIZEDTEXT("en_US","temperature"); v_attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE; UA_Server_addDataSourceVariableNode(server, UA_NODEID_NULL, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), tempName, UA_NODEID_NULL, v_attr, temperatureDataSource, NULL); }
int main(int argc, char** argv) { signal(SIGINT, stopHandler); /* catches ctrl-c */ #ifdef UA_MULTITHREADING pthread_rwlock_init(&writeLock, 0); #endif UA_Server *server = UA_Server_new(UA_ServerConfig_standard); logger = Logger_Stdout_new(); UA_Server_setLogger(server, logger); UA_ByteString certificate = loadCertificate(); UA_Server_setServerCertificate(server, certificate); UA_ByteString_deleteMembers(&certificate); UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664)); // add node with the datetime data source UA_DataSource dateDataSource = (UA_DataSource) {.handle = NULL, .read = readTimeData, .release = releaseTimeData, .write = NULL}; const UA_QualifiedName dateName = UA_QUALIFIEDNAME(1, "current time"); UA_Server_addDataSourceVariableNode(server, dateDataSource, dateName, UA_NODEID_NULL, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES)); //cpu temperature monitoring for linux machines if((temperatureFile = fopen("/sys/class/thermal/thermal_zone0/temp", "r"))){ // add node with the data source UA_DataSource temperatureDataSource = (UA_DataSource) {.handle = NULL, .read = readTemperature, .release = releaseTemperature, .write = NULL}; const UA_QualifiedName tempName = UA_QUALIFIEDNAME(1, "cpu temperature"); UA_Server_addDataSourceVariableNode(server, temperatureDataSource, tempName, UA_NODEID_NULL, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES)); }
static int infocamere_1400_init(sc_pkcs15_card_t * p15card) { sc_card_t *card = p15card->card; sc_path_t path; sc_pkcs15_id_t id, auth_id; unsigned char serial[16]; int flags; int r; int hasAuthCert = 0; const char *certLabel[] = { "User Non-repudiation Certificate", "User Authentication Certificate", "CA Certificate" }; const char *certPath[] = { "300060000000", "300060000001", "300060000002" }; const char *pinLabel[] = { "Non-repudiation PIN", "Authentication PIN" }; int retries[] = { 3, -1 }; const char *keyPath[] = { "30004000001", "30004000002" }; const char *keyLabel[] = { "Non repudiation Key", "Authentication Key" }; static int usage[] = { SC_PKCS15_PRKEY_USAGE_NONREPUDIATION, SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_SIGNRECOVER | SC_PKCS15_PRKEY_USAGE_ENCRYPT | SC_PKCS15_PRKEY_USAGE_DECRYPT }; auth_id.len = 1; id.len = 1; /* OpenSC doesn't define constants to identify BSOs for * restoring security environment, so we overload * the set_security_env function to support restore_sec_env */ set_security_env = card->ops->set_security_env; card->ops->set_security_env = infocamere_1400_set_sec_env; card->ops->compute_signature = do_sign; p15card->opts.use_cache = 1; sc_format_path("30000001", &path); r = sc_select_file(card, &path, NULL); if (r != SC_SUCCESS) return SC_ERROR_WRONG_CARD; sc_read_binary(card, 15, serial, 15, 0); serial[15] = '\0'; set_string(&p15card->serial_number, (char *)serial); set_string(&p15card->label, "Infocamere 1400 Card"); set_string(&p15card->manufacturer_id, "Infocamere"); if ((r = loadCertificate(p15card, 0, certPath[0], certLabel[0])) != SC_SUCCESS) { sc_error(p15card->card->ctx, "%s", sc_strerror(r)); return SC_ERROR_WRONG_CARD; } hasAuthCert = loadCertificate(p15card, 1, certPath[1], certLabel[1]) == SC_SUCCESS; loadCertificate(p15card, 2, certPath[2], certLabel[2]); flags = SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | SC_PKCS15_PIN_FLAG_INITIALIZED | SC_PKCS15_PIN_FLAG_NEEDS_PADDING; /* adding PINs & private keys */ sc_format_path("30004000", &path); id.value[0] = 1; sc_pkcs15emu_add_pin(p15card, &id, pinLabel[0], &path, 1, SC_PKCS15_PIN_TYPE_ASCII_NUMERIC, 5, 8, flags, retries[0], 0, SC_PKCS15_CO_FLAG_MODIFIABLE | SC_PKCS15_CO_FLAG_PRIVATE); sc_format_path(keyPath[0], &path); auth_id.value[0] = 1; sc_pkcs15emu_add_prkey(p15card, &id, keyLabel[0], SC_PKCS15_TYPE_PRKEY_RSA, 1024, usage[0], &path, 1, &auth_id, SC_PKCS15_CO_FLAG_PRIVATE); if (hasAuthCert) { sc_format_path("30004000", &path); id.value[0] = 2; sc_pkcs15emu_add_pin(p15card, &id, pinLabel[1], &path, 2, SC_PKCS15_PIN_TYPE_ASCII_NUMERIC, 5, 8, flags, retries[1], 0, SC_PKCS15_CO_FLAG_MODIFIABLE | SC_PKCS15_CO_FLAG_PRIVATE); sc_format_path(keyPath[1], &path); auth_id.value[0] = 2; sc_pkcs15emu_add_prkey(p15card, &id, keyLabel[1], SC_PKCS15_TYPE_PRKEY_RSA, 1024, usage[1], &path, 2, &auth_id, SC_PKCS15_CO_FLAG_PRIVATE); } /* return to MF */ sc_format_path("3F00", &path); r = sc_select_file(card, &path, NULL); return r; }
void SSLContextManager::addSSLContextConfig( const SSLContextConfig& ctxConfig, const SSLCacheOptions& cacheOptions, const TLSTicketKeySeeds* ticketSeeds, const folly::SocketAddress& vipAddress, const std::shared_ptr<SSLCacheProvider>& externalCache) { unsigned numCerts = 0; std::string commonName; std::string lastCertPath; std::unique_ptr<std::list<std::string>> subjectAltName; auto sslCtx = std::make_shared<SSLContext>(ctxConfig.sslVersion); for (const auto& cert : ctxConfig.certificates) { try { sslCtx->loadCertificate(cert.certPath.c_str()); } catch (const std::exception& ex) { // The exception isn't very useful without the certificate path name, // so throw a new exception that includes the path to the certificate. string msg = folly::to<string>("error loading SSL certificate ", cert.certPath, ": ", folly::exceptionStr(ex)); LOG(ERROR) << msg; throw std::runtime_error(msg); } // Verify that the Common Name and (if present) Subject Alternative Names // are the same for all the certs specified for the SSL context. numCerts++; X509* x509 = getX509(sslCtx->getSSLCtx()); auto guard = folly::makeGuard([x509] { X509_free(x509); }); auto cn = SSLUtil::getCommonName(x509); if (!cn) { throw std::runtime_error(folly::to<string>("Cannot get CN for X509 ", cert.certPath)); } auto altName = SSLUtil::getSubjectAltName(x509); VLOG(2) << "cert " << cert.certPath << " CN: " << *cn; if (altName) { altName->sort(); VLOG(2) << "cert " << cert.certPath << " SAN: " << flattenList(*altName); } else { VLOG(2) << "cert " << cert.certPath << " SAN: " << "{none}"; } if (numCerts == 1) { commonName = *cn; subjectAltName = std::move(altName); } else { if (commonName != *cn) { throw std::runtime_error(folly::to<string>("X509 ", cert.certPath, " does not have same CN as ", lastCertPath)); } if (altName == nullptr) { if (subjectAltName != nullptr) { throw std::runtime_error(folly::to<string>("X509 ", cert.certPath, " does not have same SAN as ", lastCertPath)); } } else { if ((subjectAltName == nullptr) || (*altName != *subjectAltName)) { throw std::runtime_error(folly::to<string>("X509 ", cert.certPath, " does not have same SAN as ", lastCertPath)); } } } lastCertPath = cert.certPath; // TODO t4438250 - Add ECDSA support to the crypto_ssl offload server // so we can avoid storing the ECDSA private key in the // address space of the Internet-facing process. For // now, if cert name includes "-EC" to denote elliptic // curve, we load its private key even if the server as // a whole has been configured for async crypto. if (ctxConfig.isLocalPrivateKey || (cert.certPath.find("-EC") != std::string::npos)) { // The private key lives in the same process // This needs to be called before loadPrivateKey(). if (!cert.passwordPath.empty()) { auto sslPassword = std::make_shared<PasswordInFile>(cert.passwordPath); sslCtx->passwordCollector(sslPassword); } try { sslCtx->loadPrivateKey(cert.keyPath.c_str()); } catch (const std::exception& ex) { // Throw an error that includes the key path, so the user can tell // which key had a problem. string msg = folly::to<string>("error loading private SSL key ", cert.keyPath, ": ", folly::exceptionStr(ex)); LOG(ERROR) << msg; throw std::runtime_error(msg); } } } if (!ctxConfig.isLocalPrivateKey) { enableAsyncCrypto(sslCtx); } // Let the server pick the highest performing cipher from among the client's // choices. // // Let's use a unique private key for all DH key exchanges. // // Because some old implementations choke on empty fragments, most SSL // applications disable them (it's part of SSL_OP_ALL). This // will improve performance and decrease write buffer fragmentation. sslCtx->setOptions(SSL_OP_CIPHER_SERVER_PREFERENCE | SSL_OP_SINGLE_DH_USE | SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS); // Configure SSL ciphers list if (!ctxConfig.tls11Ciphers.empty()) { // FIXME: create a dummy SSL_CTX for cipher testing purpose? It can // remove the ordering dependency // Test to see if the specified TLS1.1 ciphers are valid. Note that // these will be overwritten by the ciphers() call below. sslCtx->setCiphersOrThrow(ctxConfig.tls11Ciphers); } // Important that we do this *after* checking the TLS1.1 ciphers above, // since we test their validity by actually setting them. sslCtx->ciphers(ctxConfig.sslCiphers); // Use a fix DH param DH* dh = get_dh2048(); SSL_CTX_set_tmp_dh(sslCtx->getSSLCtx(), dh); DH_free(dh); const string& curve = ctxConfig.eccCurveName; if (!curve.empty()) { set_key_from_curve(sslCtx->getSSLCtx(), curve); } if (!ctxConfig.clientCAFile.empty()) { try { sslCtx->setVerificationOption(SSLContext::VERIFY_REQ_CLIENT_CERT); sslCtx->loadTrustedCertificates(ctxConfig.clientCAFile.c_str()); sslCtx->loadClientCAList(ctxConfig.clientCAFile.c_str()); } catch (const std::exception& ex) { string msg = folly::to<string>("error loading client CA", ctxConfig.clientCAFile, ": ", folly::exceptionStr(ex)); LOG(ERROR) << msg; throw std::runtime_error(msg); } } // - start - SSL session cache config // the internal cache never does what we want (per-thread-per-vip). // Disable it. SSLSessionCacheManager will set it appropriately. SSL_CTX_set_session_cache_mode(sslCtx->getSSLCtx(), SSL_SESS_CACHE_OFF); SSL_CTX_set_timeout(sslCtx->getSSLCtx(), cacheOptions.sslCacheTimeout.count()); std::unique_ptr<SSLSessionCacheManager> sessionCacheManager; if (ctxConfig.sessionCacheEnabled && cacheOptions.maxSSLCacheSize > 0 && cacheOptions.sslCacheFlushSize > 0) { sessionCacheManager = folly::make_unique<SSLSessionCacheManager>( cacheOptions.maxSSLCacheSize, cacheOptions.sslCacheFlushSize, sslCtx.get(), vipAddress, commonName, eventBase_, stats_, externalCache); } // - end - SSL session cache config std::unique_ptr<TLSTicketKeyManager> ticketManager = createTicketManagerHelper(sslCtx, ticketSeeds, ctxConfig, stats_); // finalize sslCtx setup by the individual features supported by openssl ctxSetupByOpensslFeature(sslCtx, ctxConfig); try { insert(sslCtx, std::move(sessionCacheManager), std::move(ticketManager), ctxConfig.isDefault); } catch (const std::exception& ex) { string msg = folly::to<string>("Error adding certificate : ", folly::exceptionStr(ex)); LOG(ERROR) << msg; throw std::runtime_error(msg); } }