String SHA256(const String& s) { SHA256_CTX context; unsigned char digest[SHA256_DIGEST_LENGTH]; if (!SHA256_Init(&context)) { BOOST_THROW_EXCEPTION(openssl_error() << boost::errinfo_api_function("SHA256_Init") << errinfo_openssl_error(ERR_get_error())); } if (!SHA256_Update(&context, (unsigned char*)s.CStr(), s.GetLength())) { BOOST_THROW_EXCEPTION(openssl_error() << boost::errinfo_api_function("SHA256_Update") << errinfo_openssl_error(ERR_get_error())); } if (!SHA256_Final(digest, &context)) { BOOST_THROW_EXCEPTION(openssl_error() << boost::errinfo_api_function("SHA256_Final") << errinfo_openssl_error(ERR_get_error())); } int i; char output[SHA256_DIGEST_LENGTH*2+1]; for (i = 0; i < 32; i++) sprintf(output + 2 * i, "%02x", digest[i]); return output; }
/** * Retrieves an X509 certificate from the specified file. * * @param pemfile The filename. * @returns An X509 certificate. */ shared_ptr<X509> GetX509Certificate(const String& pemfile) { X509 *cert; BIO *fpcert = BIO_new(BIO_s_file()); if (fpcert == NULL) { BOOST_THROW_EXCEPTION(openssl_error() << boost::errinfo_api_function("BIO_new") << errinfo_openssl_error(ERR_get_error())); } if (BIO_read_filename(fpcert, pemfile.CStr()) < 0) { BOOST_THROW_EXCEPTION(openssl_error() << boost::errinfo_api_function("BIO_read_filename") << errinfo_openssl_error(ERR_get_error()) << boost::errinfo_file_name(pemfile)); } cert = PEM_read_bio_X509_AUX(fpcert, NULL, NULL, NULL); if (cert == NULL) { BOOST_THROW_EXCEPTION(openssl_error() << boost::errinfo_api_function("PEM_read_bio_X509_AUX") << errinfo_openssl_error(ERR_get_error()) << boost::errinfo_file_name(pemfile)); } BIO_free(fpcert); return shared_ptr<X509>(cert, X509_free); }
/** * Loads a CRL and appends its certificates to the specified SSL context. * * @param context The SSL context. * @param crlPath The path to the CRL file. */ void AddCRLToSSLContext(const shared_ptr<SSL_CTX>& context, const String& crlPath) { X509_STORE *x509_store = SSL_CTX_get_cert_store(context.get()); X509_LOOKUP *lookup; lookup = X509_STORE_add_lookup(x509_store, X509_LOOKUP_file()); if (!lookup) { BOOST_THROW_EXCEPTION(openssl_error() << boost::errinfo_api_function("X509_STORE_add_lookup") << errinfo_openssl_error(ERR_get_error())); } if (X509_LOOKUP_load_file(lookup, crlPath.CStr(), X509_FILETYPE_PEM) != 0) { BOOST_THROW_EXCEPTION(openssl_error() << boost::errinfo_api_function("X509_LOOKUP_load_file") << errinfo_openssl_error(ERR_get_error()) << boost::errinfo_file_name(crlPath)); } X509_VERIFY_PARAM *param = X509_VERIFY_PARAM_new(); X509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_CRL_CHECK); X509_STORE_set1_param(x509_store, param); X509_VERIFY_PARAM_free(param); }
void pki_pkcs7::signBio(pki_x509 *crt, BIO *bio) { pki_key *privkey; EVP_PKEY *pk; STACK_OF(X509) *certstack; if (!crt) return; privkey = crt->getRefKey(); if (!privkey) throw errorEx("No private key for signing found", getClassName()); certstack = sk_X509_new_null(); pki_x509 *signer = crt->getSigner(); if (signer == crt) signer = NULL; while (signer != NULL ) { sk_X509_push(certstack, signer->getCert()); openssl_error(); if (signer == signer->getSigner() ) signer = NULL; else signer = signer->getSigner(); } if (p7) PKCS7_free(p7); pk = privkey->decryptKey(); p7 = PKCS7_sign(crt->getCert(), pk, certstack, bio, PKCS7_BINARY); EVP_PKEY_free(pk); openssl_error(); sk_X509_free(certstack); }
BIO *neo4j_openssl_new_bio(BIO *delegate, const char *hostname, int port, const neo4j_config_t *config, uint_fast32_t flags) { neo4j_logger_t *logger = neo4j_get_logger(config, "tls"); SSL_CTX *ctx = new_ctx(config, logger); if (ctx == NULL) { return NULL; } BIO *ssl_bio = BIO_new_ssl(ctx, 1); if (ssl_bio == NULL) { errno = openssl_error(logger, NEO4J_LOG_ERROR, __FILE__, __LINE__); SSL_CTX_free(ctx); goto failure; } SSL_CTX_free(ctx); BIO_push(ssl_bio, delegate); if (BIO_set_close(ssl_bio, BIO_CLOSE) != 1) { errno = openssl_error(logger, NEO4J_LOG_ERROR, __FILE__, __LINE__); goto failure; } int result = BIO_do_handshake(ssl_bio); if (result != 1) { if (result == 0) { errno = NEO4J_NO_SERVER_TLS_SUPPORT; goto failure; } errno = openssl_error(logger, NEO4J_LOG_ERROR, __FILE__, __LINE__); goto failure; } SSL *ssl = NULL; BIO_get_ssl(ssl_bio, &ssl); assert(ssl != NULL); if (verify(ssl, hostname, port, config, flags, logger)) { goto failure; } return ssl_bio; int errsv; failure: errsv = errno; BIO_free(ssl_bio); errno = errsv; return NULL; }
void pki_pkcs7::encryptBio(pki_x509 *crt, BIO *bio) { STACK_OF(X509) *certstack; if (!crt) return; certstack = sk_X509_new_null(); sk_X509_push(certstack, crt->getCert()); openssl_error(); if (p7) PKCS7_free(p7); p7 = PKCS7_encrypt(certstack, bio, EVP_des_ede3_cbc(), PKCS7_BINARY); openssl_error(); sk_X509_free(certstack); }
/** * Initializes an SSL context using the specified certificates. * * @param pubkey The public key. * @param privkey The matching private key. * @param cakey CA certificate chain file. * @returns An SSL context. */ shared_ptr<SSL_CTX> MakeSSLContext(const String& pubkey, const String& privkey, const String& cakey) { InitializeOpenSSL(); shared_ptr<SSL_CTX> sslContext = shared_ptr<SSL_CTX>(SSL_CTX_new(TLSv1_method()), SSL_CTX_free); SSL_CTX_set_mode(sslContext.get(), 0); if (!SSL_CTX_use_certificate_chain_file(sslContext.get(), pubkey.CStr())) { BOOST_THROW_EXCEPTION(openssl_error() << boost::errinfo_api_function("SSL_CTX_use_certificate_chain_file") << errinfo_openssl_error(ERR_get_error()) << boost::errinfo_file_name(pubkey)); } if (!SSL_CTX_use_PrivateKey_file(sslContext.get(), privkey.CStr(), SSL_FILETYPE_PEM)) { BOOST_THROW_EXCEPTION(openssl_error() << boost::errinfo_api_function("SSL_CTX_use_PrivateKey_file") << errinfo_openssl_error(ERR_get_error()) << boost::errinfo_file_name(privkey)); } if (!SSL_CTX_check_private_key(sslContext.get())) { BOOST_THROW_EXCEPTION(openssl_error() << boost::errinfo_api_function("SSL_CTX_check_private_key") << errinfo_openssl_error(ERR_get_error())); } if (!SSL_CTX_load_verify_locations(sslContext.get(), cakey.CStr(), NULL)) { BOOST_THROW_EXCEPTION(openssl_error() << boost::errinfo_api_function("SSL_CTX_load_verify_locations") << errinfo_openssl_error(ERR_get_error()) << boost::errinfo_file_name(cakey)); } STACK_OF(X509_NAME) *cert_names; cert_names = SSL_load_client_CA_file(cakey.CStr()); if (cert_names == NULL) { BOOST_THROW_EXCEPTION(openssl_error() << boost::errinfo_api_function("SSL_load_client_CA_file") << errinfo_openssl_error(ERR_get_error()) << boost::errinfo_file_name(cakey)); } SSL_CTX_set_client_CA_list(sslContext.get(), cert_names); return sslContext; }
void pki_pkcs7::addCert(pki_x509 *crt) { if (p7 == NULL || crt == NULL) return; PKCS7_add_certificate(p7, crt->getCert()); openssl_error(); }
int cert_fingerprint(X509* cert, char *buf, size_t n, neo4j_logger_t *logger) { unsigned char *der = NULL; int derlen = i2d_X509(cert, &der); if (derlen < 0) { errno = openssl_error(logger, NEO4J_LOG_ERROR, __FILE__, __LINE__); return -1; } unsigned char digest[EVP_MAX_MD_SIZE]; unsigned int dlen; if (sha512_digest(digest, &dlen, der, derlen, logger)) { free(der); return -1; } assert(dlen <= EVP_MAX_MD_SIZE); size_t c = 0; for (unsigned int i = 0; i < dlen && c < n; i++) { snprintf(buf + c, n - c, "%02x", digest[i]); c += 2; } return 0; }
void pki_pkcs12::writePKCS12(const QString fname) { Passwd pass; pass_info p(XCA_TITLE, tr("Please enter the password to encrypt the PKCS#12 file")); if (cert == NULL || key == NULL) { my_error(tr("No key or no Cert and no pkcs12")); } FILE *fp = fopen(QString2filename(fname), "wb"); if (fp != NULL) { if (PwDialog::execute(&p, &pass, true) != 1) { fclose(fp); return; } PKCS12 *pkcs12 = PKCS12_create(pass.data(), getIntName().toUtf8().data(), key->decryptKey(), cert->getCert(), certstack, 0, 0, 0, 0, 0); i2d_PKCS12_fp(fp, pkcs12); fclose (fp); openssl_error(); PKCS12_free(pkcs12); } else fopen_error(fname); }
void pki_x509req::fload(const QString fname) { FILE *fp = fopen_read(fname); X509_REQ *_req; int ret = 0; if (fp != NULL) { _req = PEM_read_X509_REQ(fp, NULL, NULL, NULL); if (!_req) { pki_ign_openssl_error(); rewind(fp); _req = d2i_X509_REQ_fp(fp, NULL); } fclose(fp); if (ret || pki_ign_openssl_error()) { if (_req) X509_REQ_free(_req); throw errorEx(tr("Unable to load the certificate request in file %1. Tried PEM, DER and SPKAC format.").arg(fname)); } } else { fopen_error(fname); return; } if (_req) { X509_REQ_free(request); request = _req; } autoIntName(); if (getIntName().isEmpty()) setIntName(rmslashdot(fname)); openssl_error(fname); }
void pki_pkcs7::encryptFile(pki_x509 *crt, QString filename) { BIO *bio = NULL; bio = BIO_new_file(QString2filename(filename), "r"); openssl_error(); encryptBio(crt, bio); BIO_free(bio); }
void pki_x509req::fromPEM_BIO(BIO *bio, QString name) { X509_REQ *req; req = PEM_read_bio_X509_REQ(bio, NULL, NULL, NULL); openssl_error(name); X509_REQ_free(request); request = req; }
pki_x509 *pki_pkcs7::getCert(int x) { pki_x509 *cert; cert = new pki_x509(X509_dup(sk_X509_value(getCertStack(), x))); openssl_error(); cert->autoIntName(); cert->pkiSource = imported; return cert; }
void pki_pkcs7::fromPEM_BIO(BIO *bio, QString name) { PKCS7 *_p7 = PEM_read_bio_PKCS7(bio, NULL, NULL, NULL); openssl_error(name); if (p7) PKCS7_free(p7); p7 = _p7; setIntName(rmslashdot(name)); }
a1int &a1int::setRaw(const unsigned char *data, unsigned len) { BIGNUM *bn = BN_bin2bn(data, len, NULL); if (!bn) openssl_error(); BN_to_ASN1_INTEGER(bn, in); BN_free(bn); return *this; }
a1int &a1int::setDec(const QString &s) { BIGNUM *bn=0; if (!BN_dec2bn(&bn,s.toAscii())) openssl_error(); BN_to_ASN1_INTEGER(bn, in); BN_free(bn); return *this; }
void pki_crl::fromPEM_BIO(BIO *bio, QString name) { X509_CRL*_crl; _crl = PEM_read_bio_X509_CRL(bio, NULL, NULL, NULL); openssl_error(name); X509_CRL_free(crl); crl = _crl; setIntName(rmslashdot(name)); }
QString OBJ_obj2QString(ASN1_OBJECT *a, int no_name) { char buf[512]; int len; len = OBJ_obj2txt(buf, 256, a, no_name); openssl_error(); return QString::fromAscii(buf, len); }
pki_pkcs12::pki_pkcs12(const QString d, pki_x509 *acert, pki_evp *akey) :pki_base(d) { class_name="pki_pkcs12"; key = new pki_evp(akey); cert = new pki_x509(acert); certstack = sk_X509_new_null(); openssl_error(); }
void pki_x509req::addAttribute(int nid, QString content) { if (content.isEmpty()) return; ASN1_STRING *a = QStringToAsn1(content, nid); X509_REQ_add1_attr_by_NID(request, nid, a->type, a->data, a->length); ASN1_STRING_free(a); openssl_error(QString("'%1' (%2)").arg(content).arg(OBJ_nid2ln(nid))); }
void pki_pkcs7::writeP7(XFile &file, bool PEM) const { if (!p7) return; if (PEM) PEM_write_PKCS7(file.fp(), p7); else i2d_PKCS7_fp(file.fp(), p7); openssl_error(); }
void pki_pkcs7::signFile(pki_x509 *crt, QString filename) { BIO *bio; if (!crt) return; bio = BIO_new_file(QString2filename(filename), "r"); openssl_error(); signBio(crt, bio); BIO_free(bio); }
void pki_x509req::fromPEM_BIO(BIO *bio, QString name) { X509_REQ *req; req = PEM_read_bio_X509_REQ(bio, NULL, NULL, NULL); openssl_error(name); X509_REQ_free(request); request = req; autoIntName(); if (getIntName().isEmpty()) setIntName(rmslashdot(name)); }
void *d2i_bytearray(void *(*d2i)(void *, unsigned char **, long), QByteArray &ba) { unsigned char *p, *p1; void *ret; p = p1 = (unsigned char *)ba.constData(); ret = d2i(NULL, &p1, ba.count()); ba = ba.mid(p1-p); openssl_error(); return ret; }
QByteArray i2d_bytearray(int(*i2d)(const void*, unsigned char **), const void *data) { QByteArray ba; ba.resize(i2d(data, NULL)); unsigned char *p = (unsigned char*)ba.data(); i2d(data, &p); openssl_error(); return ba; }
void pki_pkcs7::signCert(pki_x509 *crt, pki_x509 *contCert) { BIO *bio; if (!crt) return; bio = BIO_new(BIO_s_mem()); openssl_error(); i2d_X509_bio(bio, contCert->getCert()); signBio(crt, bio); BIO_free(bio); }
a1int &a1int::setHex(const QString &s) { BIGNUM *bn=0; if (s.isEmpty()) { return *this; } if (!BN_hex2bn(&bn,s.toAscii())) openssl_error(); BN_to_ASN1_INTEGER(bn, in); BN_free(bn); return *this; }
SSL_CTX *new_ctx(const neo4j_config_t *config, neo4j_logger_t *logger) { SSL_CTX *ctx = SSL_CTX_new(TLSv1_method()); if (ctx == NULL) { errno = openssl_error(logger, NEO4J_LOG_ERROR, __FILE__, __LINE__); return NULL; } if (SSL_CTX_set_cipher_list(ctx, "HIGH:!EXPORT:!aNULL@STRENGTH") != 1) { errno = openssl_error(logger, NEO4J_LOG_ERROR, __FILE__, __LINE__); goto failure; } // Necessary when using blocking sockets SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); // Caching should be done at the protocol layer anyway SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF); if (load_private_key(ctx, config, logger)) { goto failure; } if (load_certificate_authorities(ctx, config, logger)) { goto failure; } return ctx; int errsv; failure: errsv = errno; SSL_CTX_free(ctx); errno = errsv; return NULL; }
pki_pkcs12::~pki_pkcs12() { if (sk_X509_num(certstack)>0) { // free the certs itself, because we own a copy of them sk_X509_pop_free(certstack, X509_free); } if (key) { delete(key); } if (cert) { delete(cert); } openssl_error(); }