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;
}
Ejemplo n.º 2
0
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);
    }
Ejemplo n.º 3
0
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;
	}
Ejemplo n.º 5
0
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);
  }

}