SSL Cipher help in C - c

I am trying to Use SSL on top of tcp/ip to send an HTTPS request to a site using C. I have no access to curl or other standard libraries. Pretend like i can't load any libraries at all.
I need to set an SSL Profile Cipher. When I successfully use curl on my linux box to talk with the server I see: SSL Connection using ECDHE-RSA-AES128-SHA
If my options for setting the cipher are:
SSL_kRSA (RSA Key Exchange)
SSL_kEDH (tmp DH key no DH cert)
SSL_aRSA (Authenticate with RSA)
SSL-aDSS (Authenticate with DSS)
SSL_DES (DES)
SSL_3DES (3DES)
SSL_RC4 (RC4)
SSL_RC2 (RC2)
SSL_AES (AES)
SSL_MD5 (MD5)
SSL_SHA1 (SHA1)
SSL_SHA256 (SHA256)
SSL_SHA384 (SHA384)
SSL_RSA ([SSL_kRSA|SSL_aRSA] RSA)
SSL_DSS ([SSL_aDSS] Authenticate with DSS)
I can set multiple things by something like:
SSL_RSA | SSL_AES
Protocol is TLSv1.2
What should my cipher look like?

"Pretend like i can't load any libraries at all." If that is true, you will need to implement the cipher itself plus the SSL handling layer ^_^.
Assuming you are using OpenSSL and have TCP established with socket_fd, you need to create a SSL_CTX with SSL_CTX_new (SSLv23_client_method()). Normally, to set the cipher list, you use SSL_CTX_set_cipher_list(ctx, "HIGH:!aNULL:!eNULL:#STRENGTH"), see http://openssl.org/docs/apps/ciphers.html for all available options, you may specific a particular cipher.
Then create a SSL session with SSL_new(ctx) and SSL_set_fd (ssl, socket_fd), after that use SSL_connect(...), SSL_read(...)/SSL_write(...) to communicate with server.
After all have been done, SSL_shutdown(...) and SSL_Free(...), SSL_CTX_Free(...).

Related

How to obtain the key agreement algorithm used in TLS 1.3 handshake using OpenSSL API?

I was modifying the example client code given on the OpenSSL s_client page to understand a few functions. I added the following lines after the chain verification part :
const SSL_CIPHER* curr_cipher = SSL_get_current_cipher(ssl);
printf("SSL_CIPHER_standard_name: %s\n", SSL_CIPHER_standard_name(curr_cipher));
printf("SSL_get_cipher_version: %s\n", SSL_get_cipher_version(ssl));
int kx_nid = SSL_CIPHER_get_kx_nid(curr_cipher);
printf("SSL_CIPHER_get_kx_nid: %d\n", kx_nid);
printf("OBJ_nid2ln(%d): %s\n", kx_nid, OBJ_nid2ln(kx_nid));
printf("SSL_CIPHER_description: %s\n", SSL_CIPHER_description(curr_cipher, NULL, 0));
Instead of getting the key exchange algorithm used, I got the following output after connecting to random.org using TLS 1.3 :
SSL_CIPHER_standard_name: TLS_AES_256_GCM_SHA384
SSL_get_cipher_version: TLSv1.3
SSL_CIPHER_get_kx_nid: 1063
OBJ_nid2ln(1063): kx-any
SSL_CIPHER_description: TLS_AES_256_GCM_SHA384 TLSv1.3 Kx=any Au=any Enc=AESGCM(256) Mac=AEAD
The man page for SSL_CIPHER_get_kx_nid says it returns NID_kx_any for TLS 1.3. How can I programatically get the actual key agreement (NID_kx_ecdhe) and authentication protocol (NID_auth_rsa) used in the handshake from the SSL object?

SAML error "SignatureStatus: NOT_PRESENT"

UPDATE
I found that if I add a trusted cert to SPOptions.ServiceCertificates and set SPOptions.AuthenticateRequestSigningBehavior = Sustainsys.Saml2.Configuration.SigningBehavior.IfIdpWantAuthnRequestsSigned; and set IdentityProvider.WantAuthnRequestsSigned = true, the signature element is included.
Original Question:
Having troubles connecting to an IDP with the following AuthnRequest:
<saml2p:AuthnRequest xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" ID="idf299bf8aa08542d193e022cb047e5ecc" Version="2.0" IssueInstant="2019-07-23T00:10:13Z" Destination="https://example-idp.com" AssertionConsumerServiceURL="https://example-sp.com/Acs">
<saml2:Issuer>https://example-sp.com</saml2:Issuer>
</saml2p:AuthnRequest>
The IDP says: "SignatureStatus: NOT_PRESENT". I'm guessing that means that the authnrequest should have a <ds:Signature section? If so, how do I configure Sustainsys.Saml2.AspNetCore2 to include it?
The metadata xml I received from the idp contains a <ds:Signature section, but looking at the source code for Sustainsys.Saml2.AspNetCore2, it looks like that part of the metadata gets ignored when deserializing?
I'm not very familiar with the internals of SAML, so sorry if this is a silly question.
You'll want to generate a self-signed .pfx file that contains both your public cert and private key. We use azure key vault, but you could also use openssl. Lots of resources that explain how to generate one of those and load it into a c# X509Certificate2 instance.
Once you have an instance of X509Certificate2, set options.SPOptions.AuthenticateRequestSigningBehavior = Sustainsys.Saml2.Configuration.SigningBehavior.IfIdpWantAuthnRequestsSigned;
And set IdentityProvider.WantAuthnRequestsSigned = true.
And then add the X509Certificate2 instance like so: options.SPOptions.ServiceCertificates.Add(myX509Certificate2);
Then run your app and start the SAML SSO process. You can use hookbin or the like to see what it sends in the AuthnRequest for SAMLRequest. You can extract the xml from that by url decoding it and then base64 decoding it like so in javascript, for instance to confirm signature xml is set and correct: atob(decodeURIComponent(samlRequestValue))

Microsoft RPC SChannel not encrypted

I have been struggling to get a secure RPC client/server using Microsoft RPC. I am not using COM, just straight C.
I have created a Root CA certificate and created a certificate signed by this cert for the server. The certs are installed into cert stores.
RPC works fine unencrypted and it will even work with SCHANNEL setup, just not encrypted.
ServerCode:
RpcServerUseProtseqEpW(
L"ncacn_ip_tcp",
RPC_C_LISTEN_MAX_CALLS_DEFAULT,
port,
NULL);
CertOpenStore(
CERT_STORE_PROV_SYSTEM,
0,
(HCRYPTPROV)NULL,
CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_STORE_READONLY_FLAG,
L"MY")
CertFindCertificateInStore(
hStore,
X509_ASN_ENCODING|PKCS_7_ASAN_ENCODING,
CERT_FIND_SUBJEECT_STR,
subject,
NULL);
RpcCertGeneratePrincipalNameW(
ccert_ctx_server,
RPC_C_FULL_CERT_CHAIN,
serverPrincName);
schannel.dwVersion = SCHANNEL_CRED_VERSION;
schannel.cCreds = 1;
schannel.paCred = &ccert_ctx_server;
RpcServerRegisterAuthInfoW(
serverPrincName,
RPC_C_AUTHN_GSS_SCHANNEL,
NULL,
&schannel);
RpcServerRegisterIf2(
h_v1_ifspec,
NULL,
NULL,
RPC_IF_ALLOW_CALLBACKS_WITH_NO_AUTH // seems to be required by SCHANNEL
RPC_C_LISTEN_MAX_CALLS_DEFAULT,
(unsigned)-1,
SecurityCallback); SecurityCallback returns RPC_S_OK
Client Code:
RpcStringBindingComposeW(
NULL,
L"ncacn_ip_tcp",
address,
port,
NULL,
&stringBinding);
RpcBindingFronStringBindingW(
stringBinding,
hBind);
CertOpenStore(
CERT_STORE_PROV_SYSTEM,
0,
(HCRYPTPROV)NULL,
CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_STORE_READONLY_FLAG,
L"MY")
CertFindCertificateInStore(
hStore,
X509_ASN_ENCODING|PKCS_7_ASAN_ENCODING,
CERT_FIND_SUBJEECT_STR,
subject,
NULL);
RpcCertGeneratePrincipalNameW(
ccert_ctx_server,
RPC_C_FULL_CERT_CHAIN,
serverPrincName);
schannel.dwVersion = SCHANNEL_CRED_VERSION;
schannel.cCreds = 1;
schannel.paCred = &ccert_ctx_client;
RpcServerRegisterAuthInfoW(
serverPrincName,
RPC_C_AUTHN_GSS_SCHANNEL,
NULL,
&schannel);
RpcBindingSetAuthInfo(
hBind,
serverPrincName,
RPC_C_AUTHN_LEVEL_PKT_INTEGRITY,
RPC_C_AUTHN_GSS_SCHANNEL,
&schannelCred,
RPC_C_AUTHZ_NONE)
Given all of this RPC will work, but it will not be encrypted as verified with wireshark. I have worked this with a very minimal SCHANNEL structure definition and not using qos structure. Nothing makes much difference. the only thing that really makes a difference is if I change RPC_IF_ALLOW_CALLBACKS_WITH_NO_AUTH to RPC_IF_ALLOW_SECURE_ONLY. Then I get an access denied when making an RPC call. From what I understand this is the normal functionality of SCHANNEL and you must provide your own authentication within the Security Callback.
When I call RpcBindingInqAuthClient in my security callback I recieve the error 1746: The binding does not contain any authenticatioin information.
I have looked through MSDN, a the few various links scattered on the web, but there is little to know help on getting SCHANNEL working.
My choice for SCHANNEL is I can't rely on kerberos or ntlm. I am running tcp over the internet so certificates are what work for me. I can't use http because I can't setup IIS on my server, DCE seems to be even less documented than schannel.
Thanks!

GCS Signed URL client ID and sample code understanding

I am trying to implement signed URL in my code. I was trying to understand and debug the below code provided by google.
https://cloud.google.com/storage/docs/access-control#signing-code-python
Below is what my client id from Developers console looks like
zzzzzzzzzzzz-zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.apps.googleusercontent.com
Is this the client ID which the code expects? when I give this as the keytext in the code it throws "RSA key format is not supported". Any inputs greatly appreciated, I am new to this.
The complete example shows what to do basically: https://github.com/GoogleCloudPlatform/storage-signedurls-python
In cloud console, API > credentials > new credentials > service account key > key type > p12. This downloads a .p12 key
Convert key to PEM:
openssl pkcs12 -in /path/to/key.p12 -nodes -nocerts > /path/to/key.pem
Will be prompted for password: notasecret
The name of the downloaded private key is the key's thumbprint. When
inspecting the key on your computer, or using the key in your
application, you need to provide the password notasecret. Note that
while the password for all Google-issued private keys is the same
(notasecret), each key is cryptographically unique.
Write RSA key:
openssl rsa -in /path/to/key.pem -inform PEM -out /path/to/key.der -outform DER
It's your key.der you'll want to supply as your key
with open('key.der', 'rb') as k:
key = k.read()
then
import Crypto.PublicKey.RSA as RSA
...
...
private_key = RSA.importKey(key)
You may want to consider using gcloud-python for Google Cloud Storage, which among other things provides an easy way for signing a URL.

How to add PFS to socket server written in c and openssl

I try to add PFS (perfect forward secrecy) to my client-server application.
When I run a server with the following command:
openssl s_server -key ./key.pem -cert ./cert.pem -accept 443 -cipher ECDHE-RSA-AES128-SHA -tls1_2
I am able to connect with my client given the following ctx:
SSL_CTX* initCTX() {
SSL_METHOD *method;
SSL_CTX *ctx;
SSL_library_init();
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
method = TLSv1_2_client_method();
ctx = SSL_CTX_new(method);
if(ctx == NULL) {
ERR_print_errors_fp(stderr);
return NULL;
}
SSL_CTX_set_cipher_list(ctx, "ECDHE-RSA-AES128-SHA");
return ctx;
}
When I run my server application with the following ctx:
SSL_CTX* init_ssl_ctx() {
SSL_METHOD const *method;
SSL_CTX *ctx;
SSL_library_init();
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
method = TLSv1_2_server_method();
ctx = SSL_CTX_new(method);
if(ctx == NULL) {
ERR_print_errors_fp(stderr);
abort();
}
SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
SSL_CTX_set_cipher_list(ctx, "ECDHE-RSA-AES128-SHA");
// ADDITIONAL CTX MODIFICATIONS TO ENABLE ECDHE
SSL_CTX_use_certificate_file(ctx, "./cert.pem", SSL_FILETYPE_PEM);
SSL_CTX_use_PrivateKey_file(ctx, "./key.pem", SSL_FILETYPE_PEM);
return ctx;
}
and try to connect with the client, then I get an no shared cipher error.
The private key has been created with openssl genrsa.
Well my question is: How do I have to modify the ctx to add ECDHE support. I guess that I have to select a curve and I probably need to create and exchange keys for every connection.
Do I still need the private key file? And when yes — what is it used for?
Well what I actually missed was the configuration of the Diffie-Hellman parameters and the Elliptic curve Diffie-Hellman. If you do not configure them ...
the PFS cipher suites will be silently ignored.
More information and examples on how to configure and include Diffie-Hellman parameters and Elliptic curve Diffie-Hellman in your C socket server can be found here: http://wiki.openssl.org/index.php/Diffie-Hellman_parameters
... then I get an no shared cipher error.
How do I have to modify the ctx to add ECDHE support?
The cipher suite is a product of both client and server capabilities. I find that I need to add 12 to 16 to ensure most clients can be accommodated.
Here's the cipher list I use. It includes the upcoming ChaCha and Poly cipher suites, and include the downlevel client suites. If you only want ECDHE, the rdeuce the list even further.
// *_CHACHA20_POLY1305 are 3x to 4x faster than existing cipher suites.
// http://googleonlinesecurity.blogspot.com/2014/04/speeding-up-and-strengthening-https.html
// Use them if available. Normative names can be found at (TLS spec depends on IPSec spec):
// http://tools.ietf.org/html/draft-nir-ipsecme-chacha20-poly1305-01
// http://tools.ietf.org/html/draft-mavrogiannopoulos-chacha-tls-02
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305:"
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305:"
"TLS_ECDHE_ECDSA_WITH_CHACHA20_SHA:"
"TLS_ECDHE_RSA_WITH_CHACHA20_SHA:"
"TLS_DHE_RSA_WITH_CHACHA20_POLY1305:"
"TLS_RSA_WITH_CHACHA20_POLY1305:"
"TLS_DHE_RSA_WITH_CHACHA20_SHA:"
"TLS_RSA_WITH_CHACHA20_SHA:"
// Done with bleeding edge, back to TLS v1.2 and below
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:"
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:"
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:"
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:"
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:"
"TLS_DHE_DSS_WITH_AES_256_GCM_SHA384:"
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:"
"TLS_DHE_DSS_WITH_AES_128_GCM_SHA256:"
// TLS v1.0 (with some SSLv3 interop)
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA384:"
"TLS_DHE_DSS_WITH_AES_256_CBC_SHA256:"
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA:"
"TLS_DHE_DSS_WITH_AES_128_CBC_SHA:"
"TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:"
"TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA:"
"SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA:"
"SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA:"
// RSA key transport sucks, but they are needed as a fallback.
// For example, microsoft.com fails under all versions of TLS
// if they are not included. If only TLS 1.0 is available at
// the client, then google.com will fail too. TLS v1.3 is
// trying to deprecate them, so it will be interesteng to see
// what happens.
"TLS_RSA_WITH_AES_256_CBC_SHA256:"
"TLS_RSA_WITH_AES_256_CBC_SHA:"
"TLS_RSA_WITH_AES_128_CBC_SHA256:"
"TLS_RSA_WITH_AES_128_CBC_SHA:"
The ChaCha/Poly cipher suites are available in OpenSSL 1.0.2. So you can test Google's implementation if interested.
The RFCs do not specify who picks the cipher. By convention, the server usually honors the client's preference. To ensure your server picks the cipher suite, you should add SSL_OP_CIPHER_SERVER_PREFERENCE to the server's context options. See SSL_CTX_set_options(3).

Resources