I am trying to code a web service client in a RHEL 4 system (openssl 0.9.8b) (upgrade is not an option). I got the CA cert file to use, with two certificates, one is a self-signed root certificate. It works with "openssl s_client", but not from code. There I get error 7 (SSL certificate validation failed) from SSL_get_verify_result.
I made a test program, here are the basic parts:
SSL_library_init();
SSL_load_error_strings();
ctx = SSL_CTX_new(SSLv23_method());
SSL_CTX_load_verify_locations(ctx, "/etc/pki/mycert/cacert.pem", 0);
ssl = SSL_new(ctx);
sbio = BIO_new_socket(sock, BIO_NOCLOSE); /* The socket is already connected */
SSL_set_bio(ssl, sbio, sbio);
SSL_connect(ssl);
err = SSL_get_verify_result(ssl);
The connection works and the server sends its certificate; I have dumped it out with PEM_write_X509 and verified that it is accepted by "openssl verify".
I have used
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_callback);
to write out the steps of the verification in a callback function:
static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
{
char buf[256];
X509 *err_cert;
int err, depth;
err_cert = X509_STORE_CTX_get_current_cert(ctx);
err = X509_STORE_CTX_get_error(ctx);
depth = X509_STORE_CTX_get_error_depth(ctx);
X509_NAME_oneline(X509_get_subject_name(err_cert), buf, 256);
if (!preverify_ok)
printf("verify error:num=%d:%s:depth=%d:%s\n", err,
X509_verify_cert_error_string(err), depth, buf);
else
printf("Preverify OK, depth=%d:%s, err=%d\n", depth, buf, err);
...
The output of this is (some certificate data replaced with "..."):
Preverify OK, depth=2:/ST=GP/L=JHB/C ... QA Root CA 01, err=0
Preverify OK, depth=1:/C=ZA/DC=za/DC ... QA Issue CA 01, err=0
verify error:num=7:certificate signature failure:depth=0:/C=ZA ...
When running "openssl s_client" with this CA cert file as "-CAfile", the output starts with:
depth=2 /ST=GP/L=JHB/C ... QA Root CA 01
verify return:1
depth=1 /C=ZA/DC=za/DC ... QA Issue CA 01
verify return:1
depth=0 /C=ZA/ST ...
verify return:1
So what is the difference between what "openssl s_client" is doing, and what the code is doing?
I got it to work by adding "OpenSSL_add_all_algorithms()" to the code. It turned out that the algorithm used by the server cert was not found. The difference between the code and the openssl s_client command is obviously this call.
The code in the test program was taken from the Axis2/C source code, since my client is based on Axis2/C. So this call is missing there too.
Related
The server is Liberty on z/OS. The server cert is self signed.
Command issued:
openssl s_client -CApath /home/ibmsys1 -showcerts -connect zito-zos.ddns.net:19181 < /dev/null
The following is returned:
CONNECTED(00000003)
depth=0 O = IBM, OU = C54WLP, CN = START1
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 O = IBM, OU = C54WLP, CN = START1
verify error:num=21:unable to verify the first certificate
verify return:1
Certificate chain
0 s:O = IBM, OU = C54WLP, CN = START1
i:O = IBM, OU = C54WLP, CN = C54WLP Sample Certification Authority
The first in the chain is the server cert.
The second is the signing certauth.
In the folder given as CApath I placed "cacert.crt" that includes the certauth signing cert for
"CN = C54WLP Sample Certification Authority".
What is causing this error?
The following approach for connecting an https page with OpenSSL seems to work for most pages, but not for sheets.googleapis.com.
// initialize OpenSLL
SSL_library_init();
SSL_load_error_strings();
SSL_CTX* ctx = SSL_CTX_new(SSLv23_client_method());
// create context
SSL_CTX_set_ecdh_auto(ctx, 1);
wstring strHostname = L"sheets.googleapis.com";
wstring strPort = L"443";
SOCKET s = http_server_connect(strHostname, strPort);
// make socket non blocking for the timeout
unsigned long mode = 1;
ioctlsocket(s, FIONBIO, &mode);
SSL* ssl = SSL_new(ctx);
SSL_set_fd(ssl, (int)s);
int res = SSL_ERROR_NONE;
while ((res = SSL_connect(ssl)) != 1)
{
int error = SSL_get_error(ssl, res);
fd_set fds;
FD_ZERO(&fds);
FD_SET(s, &fds);
switch (error)
{
case SSL_ERROR_WANT_READ:
select(int(s + 1), &fds, NULL, NULL, NULL);
break;
case SSL_ERROR_WANT_WRITE:
select(int(s + 1), NULL, &fds, NULL, NULL);
break;
case SSL_ERROR_SYSCALL:
printf("SSL_ERROR_SYSCALL\n");
break;
}
}
Running this code the first SSL_connect shows the expected SSL_ERROR_WANT_READ and the second call does not show and error. However by checking the connection with Wireshark you see, that the server is resetting the connection. Using a blocking socket works without any problem.
I'm aware that there is a question with almost the same content which was answered by the code above, but this does not work for the google api page for any reason. Does anybody have a hint how to overcome this problem.
I've tested it on various OpenSSL versions including the latest 1.1.1d
Meanwhile I have figured out the issue. I have to set the hostname for the ssl connection by SSL_set_tlsext_host_name.
The interesting thing is that this information seems to be cached. After Removing the command later on, the code still works.
I am creating a c++ project using the net-snmp libraries i build, I was able to interface with my hardware via SNMP v2c as well as SNMP v3 (authNoPriv). However, this was unsuccessful when I tried using authPriv, is there any advice on this?
What I suspect is that net-snmp does not support AES.
When i tried to run net-snmp directly, I see for the privacy protocol there's only the option for DES. So I would like to confirm does net-snmp supports both AES128 and DES privacy protocol?
For authNoPriv, I was returned with the Authentication failure when I used SHA-1 Authentication Protocol
For authPriv, I couldn't establish any connection with the SNMP hardware.
I suspect there is something wrong in my code, as there was no issue with authNoPriv with MD5 Authentication Protocol, but the above errors occur when I configured to the respective the security protocol.
// Definitions
const char * user = "snmpuser";
const char * our_v3_passphrase = "passphrase";
const char * our_v3_privphrase = "privphrase";
struct snmp_session session;
SOCK_STARTUP;
// Initialize the SNMP library
snmp_sess_init(&session);
session.peername = _strdup(argv[1])
// set the SNMP version number
session.version = SNMP_VERSION_3;
session.securityNameLen = strlen(session.securityName);
// set the security level
session.securityLevel = SNMP_SEC_LEVEL_AUTHPRIV; // SNMP_SEC_LEVEL_AUTHNOPRIV (for authNoPriv)
// set the authentication protocol
session.securityAuthProto = usmHMACMD5AuthProtocol; // usmHMACSHA1AuthProtocol
session.securityAuthProtoLen = USM_AUTH_PROTO_MD5_LEN; // USM_AUTH_PROTO_SHA_LEN
session.securityAuthKeyLen = USM_AUTH_KU_LEN;
// set authentication key to a hashed version of passphrase
if (generate_Ku(session.securityAuthProto, session.securityAuthProtoLen, (u_char *)our_v3_passphrase, strlen(our_v3_passphrase), session.securityAuthKey, &session.securityAuthKeyLen) != SNMPERR_SUCCESS) {
snmp_perror(argv[0]);
snmp_log(LOG_ERR, "Error generating Ku from authentication passphrase. \n");
SOCK_CLEANUP;
exit(1);
}
// set the privacy protocol
session.securityPrivProto = usmAES128PrivProtocol; // usmDESPrivProtocol
session.securityAuthProtoLen = USM_PRIV_PROTO_AES128_LEN; // USM_PRIV_PROTO_DES_LEN
session.securityAuthKeyLen = USM_PRIV_KU_LEN;
// set privacy key to a hashed version of privphrase
if (generate_Ku(session.securityAuthProto, session.securityAuthProtoLen, (u_char *)our_v3_privphrase, strlen(our_v3_privphrase), session.securityPrivKey, &session.securityPrivKeyLen) != SNMPERR_SUCCESS) {
snmp_perror(argv[0]);
snmp_log(LOG_ERR, "Error generating Ku from authentication passphrase. \n");
SOCK_CLEANUP;
exit(1);
}
I wish to parse and display the contents of an Authenticode PKCS#7 signature as extracted from a Window PE binary's Security Directory.
I can use OpenSSL to do this on the command line with "openssl pkcs7 -text -in extracted_signature.pks -inform DER -print_certs", however I need to do this via C/C++ and the Windows API. I cannot use the OpenSSL library itself.
Using the CryptDecodeObjectEx API I can begin to decode the extracted signature:
CRYPT_CONTENT_INFO * content_info;
DWORD len;
CryptDecodeObjectEx(
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
PKCS_CONTENT_INFO,
pointer_to_extracted_signature,
length_of_extracted_signature,
CRYPT_DECODE_ALLOC_FLAG,
NULL,
&content_info,
&len
);
The above call completes successfully and content_info->pszObjId will have an OID of "1.2.840.113549.1.7.2" (szOID_RSA_signedData) however I am unable to find the structures needed to continue decoding. The available OID's for CryptDecodeObjectEx are listed here.
Can anybody please advise how to decode an Authenticode PKCS#7 signature via the Windows API?
I have found the correct way to decode an Authenticode PKCS#7 signature is to use CryptQueryObject with the CERT_QUERY_OBJECT_BLOB and CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED flags set. Code snippit below for anybody who might need to do this.
CERT_BLOB cert_blob;
HCERTSTORE cert_store = NULL;
HCRYPTMSG cert_msg = NULL;
cert_blob.pbData = pointer_to_extracted_signature;
cert_blob.cbData = length_of_extracted_signature;
CryptQueryObject(
CERT_QUERY_OBJECT_BLOB,
&cert_blob,
CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED,
CERT_QUERY_FORMAT_FLAG_BINARY,
0,
NULL,
NULL,
NULL,
&cert_store,
&cert_msg,
NULL
);
PCCERT_CONTEXT next_cert = NULL;
while( (next_cert = CertEnumCertificatesInStore( cert_store, next_cert ) ) != NULL )
{
// process next_cert...
}
Since openssl is deprecated in osx 10.7+, I'd like to switch from openssl to the internal osx keychain and crypto function.
But now I am stuck on asymmetric encryption/decryption.
How can I do encryption/decryption of a randomly generated symmetric key with a asymmetric (RSA) key. With openssl it's quite easy.
In the apple dev docs, they say that CommonCrypto supports asymmetric encryption, but while checking the headers, I can only see support for symmetric stuff.
Any hints?
Take a look at Cryptographic Message Syntax Services and see if that can do what you need.
Also, you're misreading the OpenSSL thing just a bit. The OpenSSL libraries that ship with the OS are deprecated. That doesn't mean you can't continue to use OpenSSL. OpenSSL is Open Source, and there's nothing stopping you from downloading it and using it freely in your application.
Apple's deprecation just means that if you use OpenSSL, you need to include your own copy of the OpenSSL libraries so that you are responsible for keeping your OpenSSL library up-to-date and for fixing any breakage that occurs whenever you do so. :-)
And if not, the iOS asymmetric encryption and decryption functions (SecKeyEncrypt and SecKeyDecrypt) do exist in OS X, and the iOS header even shows that they are available in OS X. I'm not sure why they aren't in the OS X SDK. I filed a bug, and it was marked as a dup.
It probably would not be possible for Apple to remove those functions in the future without breaking the Simulator, but if you're submitting to the app store and they give you grief about using them, here's a roughly compatible replacement for SecKeyEncrypt built using the Security Transforms API:
// Workaround for SecKeyEncrypt not really being public API in OS X
OSStatus OSXSecKeyEncrypt ( SecKeyRef key, SecPadding padding, const uint8_t *plainText, size_t plainTextLen, uint8_t *cipherText, size_t *cipherTextLen )
{
CFMutableDictionaryRef parameters = CFDictionaryCreateMutable(
kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(parameters, kSecAttrKeyType, kSecAttrKeyTypeAES);
CFErrorRef error = NULL;
SecTransformRef encrypt = SecEncryptTransformCreate(key, &error);
if (error) {
AFNSLog(#"Encryption failed: %#\n", (__bridge NSError *)error);
return (OSStatus)[(__bridge NSError *)error code];
}
SecTransformSetAttribute(
encrypt,
kSecPaddingKey,
NULL, // kSecPaddingPKCS1Key (rdar://13661366 : NULL means kSecPaddingPKCS1Key and
// kSecPaddingPKCS1Key fails horribly)
&error);
CFDataRef sourceData = CFDataCreate(kCFAllocatorDefault, plainText, plainTextLen);
SecTransformSetAttribute(encrypt, kSecTransformInputAttributeName,
sourceData, &error);
CFDataRef encryptedData = SecTransformExecute(encrypt, &error);
if (error) {
AFNSLog(#"Encryption failed: %#\n", (__bridge NSError *)error);
return (OSStatus)[(__bridge NSError *)error code];
}
if ((unsigned long)CFDataGetLength(encryptedData) > *cipherTextLen) {
return errSecBufferTooSmall;
}
*cipherTextLen = CFDataGetLength(encryptedData);
CFDataGetBytes(encryptedData, CFRangeMake(0, *cipherTextLen), cipherText);
return noErr;
}
You should be able to adapt the code for decryption fairly easily; I didn't need it for my purposes, so I didn't write that function.