Bouncy Castle: Creating CMS (a.k.a. PKCS7) certificate? - ssl

How do I create a CMS (a.k.a. PKCS7) certificate?
The following bouncy castle code creates a PKCS12 certificate:
ASN1EncodableVector v = new ASN1EncodableVector();
v.add(tbsCert);
v.add(sigAlgId);
v.add(new DERBitString(signature));
X509CertificateObject clientCert = new X509CertificateObject(Certificate.getInstance(new DERSequence(v)));
PKCS12BagAttributeCarrier bagCert = clientCert;
bagCert.setBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName,
new DERBMPString("Certificate for IPSec WLAN access"));
bagCert.setBagAttribute(
PKCSObjectIdentifiers.pkcs_9_at_localKeyId,
new SubjectKeyIdentifierStructure(pubKey));
I see there is CMSSignedDataGenerator in the API, but I am not if it's applicable to my case and if so how....
I also don't understand why, if the created certificate is a PKCS12 one, then why do they use PKCS9 variables in order to built it.

There is no such thing as a CMS certificate or PKCS#12 certificate.
CMS is the cryptographic message syntax. It specifies a container format that may contain X5.09 compatible certificates of the signer. PKCS#12 is a container format for cryptographic objects, it is often used to store one or more certificate/private key pairs. PKCS#9 explicitly defines attributes for X5.09 certificates.
You probably just need to build an X5.09 certificate, possibly using PKCS#9 defined attributes. Those certificates should be compatible with both CMS and PKCS#12.

Related

What's meaning of client SSL authentication and server SSL authentication in X509TrustManager?

I understand "certificate chain provided by the peer", if certificate provided by the peer is in the X509TrustManager, the certificate is trusted, so is it just need a checkTrusted instead of checkClientTrusted and checkServerTrusted, i don't understand what's the difference? Can anyone explains?
https://docs.oracle.com/javase/7/docs/api/javax/net/ssl/X509TrustManager.html
void checkClientTrusted(X509Certificate[] chain, String authType):
Given the partial or complete certificate chain provided by the peer, build a certificate path to a trusted root and return if it can be validated and is trusted for client SSL authentication based on the authentication type.
void checkServerTrusted(X509Certificate[] chain, String authType):
Given the partial or complete certificate chain provided by the peer, build a certificate path to a trusted root and return if it can be validated and is trusted for server SSL authentication based on the authentication type.
In the early SSL/TLS protocols that existed when JSSE was designed, there was a significant difference between the constraints on and thus validation of server cert (linked to the key_exchange portion of the ciphersuite) versus client cert (mostly independent of key_exchange but controlled by CertReq); see rfc2246 7.4.2 and 7.4.4 (modified by rfc4492 2 and 3). Although authType is a String in both checkServer and checkClient, the values in it and the processing of them in the default TrustManager were significantly different.
TLS1.2, implemented (along with 1.1) by Java 7 and early 8, changed the cert constraints to also use a new signature_algorithms extension (from client) and field (from server) in combination with the prior fields. As a result in Java 7 up the interface you link is functionally replaced by a subtype class https://docs.oracle.com/javase/7/docs/api/javax/net/ssl/X509ExtendedTrustManager.html which in addition to the new constraint checks also moves to the JSSE layer only in checkServer the hostname checking aka endpoint identification formerly done at a higher level like HttpsURLConnection (if at all). The extended class additionally takes an SSLSocket or SSLEngine argument (as applicable) which allows access to the additional information for sigalgs and hostname.
Finally TLS1.3, implemented in java 11 up and backported to 8u261 up, uses only extensions, now two of them, and not the ciphersuite at all, for cert selection and checking. In 1.3 the extended API is still called but the value in authType is meaningless and must not be used, and in at least some cases I have looked at is in fact empty, so the actual (rfc5280) validation is in fact the same for both directions. But as above checkServer does endpoint identification if applicable while checkClient does not.
See an actual difference in https://security.stackexchange.com/questions/158339/ssl-tls-certificate-chain-validation-result-in-invalid-authentication-type-d (note: 2017 was before TLS1.3 existed)
and compare javax.net.ssl.SSLContext to trust everything sslContext.init(keyManagerFactory.getKeyManagers(), ???, new SecureRandom()); .

How Can I Verify the Contents of a Subject Alternate Name in URI Format Using Apache mod_ssl Variables?

I am working on a web service project which requires that clients connecting to my service authenticate themselves via X.509 certificates as part of a Mutual Authentication TLS negotiation. In addition to linking the client certificate to a specific PKI trust chain, my requirements dictate that I must verify specific values within the certificate. Specifically, the subject DN must contain one OU with a predetermined value, and the certificate must contain one subjectAltName with a different predetermined value in URI format.
I am using Apache httpd 2.4.6 on a CentOS 7 system, and am able to satisfy most of these requirements fairly easily with standard Apache configuration directives leveraging common mod_ssl variables, with one notable exception: I cannot seem to find a variable that allows me to access a subjectAltName value in URI format. Looking at the mod_ssl documentation found here:
https://httpd.apache.org/docs/2.4/mod/mod_ssl.html
I can see variables for the following subjectAltName formats:
SSL_CLIENT_SAN_Email_n - Client certificate's subjectAltName extension entries of type rfc822Name
SSL_CLIENT_SAN_DNS_n - Client certificate's subjectAltName extension entries of type dNSName
SSL_CLIENT_SAN_OTHER_msUPN_n - Client certificate's subjectAltName extension entries of type otherName, Microsoft User Principal Name form (OID 1.3.6.1.4.1.311.20.2.3)
Given that URI is a distinct and valid format for subjectAltName values as defined in RFC 5280 (X.509/PKI) section 4.2.1.6, I'm at a loss for why mod_ssl would not provide access to subjectAltNames in this format. Is there a variable that provides this functionality which I am simply not seeing in the documentation?
Further reviewing the mod_ssl source code, it is clear that extracting SAN values in URI format for use in variables is simply not currently supported, as noted by this comment:
/*
* Not implemented right now:
* GEN_X400 (x400Address)
* GEN_DIRNAME (directoryName)
* GEN_EDIPARTY (ediPartyName)
* GEN_URI (uniformResourceIdentifier)
* GEN_IPADD (iPAddress)
* GEN_RID (registeredID)
*/
in https://github.com/apache/httpd/blob/5f32ea94af5f1e7ea68d6fca58f0ac2478cc18c5/modules/ssl/ssl_util_ssl.c
As such, the answer to my question is apparently that there is not presently a variable I can use for this purpose, and fulfilling this requirement will necessitate a workaround (or an implementation of GEN_URI pushed to mod_ssl).

openssl 1.0.2j, how to force server to choose ECDH* ciphers

I have client server which uses opensl 1.0.2j, and using RSA:4096 key and certificate and want to force the server to use only the following ciphers.
ECDHE-RSA-AES256-GCM-SHA384
ECDHE-RSA-AES256-SHA384
ECDH-RSA-AES128-GCM-SHA256
ECDH-RSA-AES128-SHA256
DHE-RSA-AES256-GCM-SHA384
DHE-RSA-AES256-SHA256
DHE-RSA-AES128-GCM-SHA256
DHE-RSA-AES128-SHA256
My server side code will look like below.
method = SSLv23_server_method();
ctx = SSL_CTX_new(method);
SSL_CTX_set_cipher_list(ctx, "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDH-RSA-AES128-GCM-SHA256:ECDH-RSA-AES128-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-SHA256");
SSL_CTX_set_ecdh_auto(ctx, 1);
SSL_CTX_set_tmp_dh(ctx, dh);
SSL_CTX_set_tmp_ecdh(ctx, ecdh);
SSL_CTX_use_certificate_file(ctx, certFilePath, SSL_FILETYPE_PEM);
SSL_CTX_use_PrivateKey_file(ctx, privKeyPath, SSL_FILETYPE_PEM)
SSL_accept()
My client side code will look like as below
method = SSLv23_server_method();
ctx = SSL_CTX_new(method);
SSL_CTX_set_cipher_list(ctx, "ECDH-RSA-AES128-GCM-SHA256:ECDH-RSA-AES128-SHA256:ECDH-ECDSA-AES128-GCM-SHA256:ECDH-ECDSA-AES128-SHA256");
SSL_CTX_set_ecdh_auto(ctx, 1);
SSL_CTX_set_tmp_dh(ctx, dh);
SSL_CTX_set_tmp_ecdh(ctx, ecdh);
SSL_CTX_use_certificate_file(ctx, certFilePath, SSL_FILETYPE_PEM);
SSL_CTX_use_PrivateKey_file(ctx, privKeyPath, SSL_FILETYPE_PEM)
SSL_connect()
The last step ssl_accept() on the server fails with
err: 336027900 'error:140760FC:SSL routines:SSL23_GET_CLIENT_HELLO:unknown protocol'
If i use ECDHE*RSA* or DHE*RSA* ciphers on the client side, it is working fine.
Could you please let me know what I am missing?
Edit: server's certificate(certFilePath) contains an RSA public key not the ECDH public key.
Meta: answer only up to TLS1.2; 1.3 no longer has keyexchange and authentication in ciphersuite.
First, it makes no sense to call both set_ecdh_auto and set_tmp_ecdh -- those are mutually exclusive. Also your server doesn't request client authentication, so configuring a self-cert&key on the client is useless. OTOH your server is using a selfsigned cert which probably isn't in the client's default truststore, so you may need to configure the client truststore (there are several approaches to doing that).
Second, 'static' ECDH ciphersuites are quite different from ECDHE suites, just as 'static' DH suites are different from DHE suites. Both static forms are not widely implemented and very little used because they generally offer no benefit; in particular OpenSSL 1.1.0 and up no longer implement them, so your code becomes obsolete in about a year if I remember the schedule correctly.
To be exact, DH-RSA suites require a cert containing a DH key (which permits keyAgreement), and for TLS<=1.1 the cert must be issued by a CA using an RSA key; for 1.2 this latter restriction is removed. No public CA will issue a cert for a DH key, and even doing it yourself isn't easy; see https://security.stackexchange.com/questions/44251/openssl-generate-different-type-of-self-signed-certificate and (my) https://crypto.stackexchange.com/questions/19452/static-dh-static-ecdh-certificate-using-openssl/ .
ECDH-RSA suites similarly require a cert containing an ECC key which permits keyAgreement, and issued by RSA if <=1.1; this is somewhat easier because the key (and CSR) for ECDH is the same as for ECDSA and only KeyUsage needs to differ. For your self-created and self-signed case, it's easy, just generate an ECC key and cert (automatically signed with ECDSA).
But last, this shouldn't cause 'unknown protocol'; it would cause 'no shared cipher' and handshake_failure. The code you've shown shouldn't cause 'unknown protocol', so you probably need to investigate and fix that first. You might try using commandline s_client instead especially with its -debug or -msg hooks, or -trace if you have compiled that in.

how do I use a smart card as KeyStore for client authentication during SSL/TLS?

have been attempting to use a PKCS#11 token (Smart card) as a KeyStore (not the TrustStore) on the client side for client authentication of a TLS connection. However, the SSL handshake fails with a SSLException with the message:
Unexpectedly, privatekey is not an RSA private key.
This cannot be true because the private key/certificate pairs on the smart card are RSA keys. Am I missing some configuration to use a smart card as a KeyStore for JSSE?
Here are my configuration details:
Firstly, configured the Sun PKCS#11 Provider to work with an 'ActivCard' dll that interfaces with the smart card. The Sun PKCS#11 Provider configuration file just contains the 'name' and 'library' attributes.
The instantiation of the SunPKCS#11 provider looks like this:
java.security.AuthProvider provider =
new sun.security.pkcs11.SunPKCS11.SunPKCS11(<Configuration file>);
Then, the instantiation of a java.security.KeyStore object from the smart card is done using this code below:
KeyStore.ProtectionParameter thePasswordProtection =
new KeyStore.PasswordProtection( null );
KeyStore.Builder theBuilder =
KeyStore.Builder.newInstance( "PKCS11", provider, thePasswordProtection );
java.security.KeyStore theKeyStore = theBuilder.getKeyStore();
Moreover, this instantiated KeyStore is used to make a KeyManagerFactory to be used by JSSE using the code below:
KeyManagerFactory kmf = javax.net.ssl.KeyManagerFactory.
getInstance( "SunX509", "SunJSSE" );
kmf.init( theKeyStore, <smart card pin> );
This KeyManagerFactory is used to then initialize an SSLContext which is then used to instantiate an SSLSocket.
As per instructions in Oracle's JSSERefGuide for Java 6, this is all I need to do for it to work. Although it is not required to set the below system properties while using the keystores programmatically, I also tried adding the system properties:
javax.net.ssl.keyStoreType to PKCS11,
javax.net.ssl.keyStore to NONE and
javax.net.ssl.keyStoreProvider to the name specified for the Sun PKCS#11 provider in its configuration file.
Any ideas what I am doing wrong here? Any pointers or thoughts would be much appreciated.

Using X.509 certificate with OpenSSL in iPhone App

I'm trying to figure out how to use the self compiled OpenSSL API to load an existing X.509 certificate (.crt) which I have included in Xcode's project structure.
I need a X509 object (from OpenSSL x509.h) which should be created/loaded from an existing file. Including the header works fine but I really can't find a way to load an existing certificate... There are sooo many methods in the x509.h but no sufficient documentation.
Thanks,
Chris
If you've read the character data into a char* s, something like
BIO* bio = BIO_new_mem_buf((void*)s, -1);
X509* cert = 0;
PEM_read_bio_X509(bio, &cert, 0, NULL);
...
X509_free(cert);
BIO_free(bio);