OpenSSL pkcs12 Export chained CA Certs separately - ssl

I have a cert chain that looks like this:
Global CA
Intermediate CA
MyCert
I am using openssl.exe to create .cer files from MyCert.pfx, and I want the generated cert to contain the client cert first, followed by the Intermediate CA cert. The end result should look something like this:
Bag Attributes
<mycert attributes>
-----BEGIN CERTIFICATE-----
<mycert data>
-----END CERTIFICATE-----
Bag Attributes
<intermediate ca attributes>
-----BEGIN CERTIFICATE-----
<intermediate ca data>
-----END CERTIFICATE-----
I can get the first cert by running
openssl pkcs12 -in MyCert.pfx -clcerts -nokeys -password pass:mypassword -out mycert.cer
And I can run the command to get the CA certs in the chain like this
openssl pkcs12 -in MyCert.pfx -cacerts -nokeys -password pass:mypassword -out cacert.cer
But this generates a file with both the Global CA and the Intermediate CA certs.
Is there a way to specify only the Intermediate CA by CN or something?
I can get the content out of the file but was hoping for a cleaner solution.

Well I opted for the gross way... Here it is.
# Generate the client cert
&"$opensslPath\openssl.exe" pkcs12 -in "$($filepathforCert).pfx" -clcerts -nokeys -out "$($filepathforCert)-fullchain.crt" -password pass:$certPassword
# Generate the CA certs in the chain
&"$opensslPath\openssl.exe" pkcs12 -in "$($filepathforCert).pfx" -cacerts -nokeys -out "$($filepathforCACert).crt" -password pass:$certPassword
# Combine certs
# The common name for the intermediate CA should be the same until 2031
$intermediateCaCn = "CN = DigiCert TLS RSA SHA256 2020 CA1"
$certBeginToken = "-----BEGIN CERTIFICATE-----"
$certEndToken = "-----END CERTIFICATE-----"
$intermediateCACertStart = (Select-String -Pattern $intermediateCaCn -Path "$($filepathforCACert).crt" -SimpleMatch | select-object -First 1).LineNumber
$firstCertStart = (Select-String -Pattern $certBeginToken -Path "$($filepathforCACert).crt" -SimpleMatch | select-object -First 1).LineNumber
$intermediateStartLine = 0
$intermediateEndLine = 0
# The beginning of the cert will always start after the CN
if($intermediateCACertStart -gt $firstCertStart)
{
$intermediateStartLine = (Select-String -Pattern $certBeginToken -Path "$($filepathforCACert).crt" -SimpleMatch | select-object -Last 1).LineNumber
$intermediateEndLine = (Select-String -Pattern $certEndToken -Path "$($filepathforCACert).crt" -SimpleMatch | select-object -Last 1).LineNumber
}
else
{
$intermediateStartLine = $firstCertStart
$intermediateEndLine = (Select-String -Pattern $certEndToken -Path "$($filepathforCACert).crt" -SimpleMatch | select-object -First 1).LineNumber
}
# size of the cert, including the delimiters
$lineCount = ($intermediateEndLine - $intermediateStartLine)
$certContent = (Get-Content -Path "$($filepathforCACert).crt"| Select-Object -Skip ($intermediateStartLine - 1) -First ($lineCount +1))
Add-Content -Path "$($filepathforCert)-fullchain.crt" -Value $certContent

Related

Fingerprint of certificate request (CSR)

I've a certificate request (see bottom) of which I'd like get fingerprint preferably from command-line (Unix). If my goal was only to verify integrity of a PEM file on two machines I could just use e.g. sha256sum csr.pem value but I'd like to get the same fingerprint as Puppet does:
puppet:~# puppetserver ca list --all
Requested Certificates:
testbox (SHA256) 7C:8C:A2:2C:17:42:C1:B9:55:A0:1D:EE:0D:C1:B0:65:B0:B4:AF:83:68:77:A8:0D:C4:6C:B1:41:25:FF:E7:C2
This fingerprint value is printed on both testbox and puppet machines when bootstrapping testbox and only thing they both share is the CA certificate (private key of which is stored on puppet). So the algorithm shouldn't require any private keys on input.
I assume the algorithm is standard, but I don't know cryptographic formats and openssl enough to figure out how to get it, and I'd specifically like to use openssl or some other widely available command line utility (i.e. not Ruby).
One of my failed attempts:
testbox:~# openssl x509 -fingerprint -in /etc/puppetlabs/puppet/ssl/certificate_requests/testbox.pem
unable to load certificate
139644407518336:error:0909006C:PEM routines:get_name:no start line:../crypto/pem/pem_lib.c:745:Expecting: TRUSTED CERTIFICATE
Here's the actual certificate request:
testbox:~# cat /etc/puppetlabs/puppet/ssl/certificate_requests/testbox.pem
-----BEGIN CERTIFICATE REQUEST-----
MIIEVzCCAj8CAQAwEjEQMA4GA1UEAwwHdGVzdGJveDCCAiIwDQYJKoZIhvcNAQEB
BQADggIPADCCAgoCggIBAKAT6FPs6RkT30lnNk0wpfhLtjrrAr/YdyDCUVTjV5jL
23iuLLSHes7yog/gACitGqCOnSz7J95OUtfGV+ACV8AEcyNpQazOqHhcLh15CYa7
8fDyVsoLzHWUKDMXhNllYrJFOoEDU/IP/y5hdS6e56pPZCVwYRxg9pjtvOX/FyUA
vXFA94IvqAgR2HdD7Vbr11mSmVNJuP9bWimhizvpzG4g3Xacvz7BhEZC5v/tIuH6
zaQtKCoBoxTFQhlFhY1F0iIMIjbTFTUuzPjCh5pMhXMxm0rgpH0SkvJp8bzesCGX
34JIDCOo6R197IttvbPh+6J91nMReOrYl4WAIMFHMz9L2dEClKbT0qWKjTHSUB6E
Pkia6d/gQzM4UcfP2NGAPnaWv3HZJPy6LnOHFoaxkfiMVGMlKISqF8cbkhGEneX0
V3Q8z60BAdr1q2i2rmPQkhp0MLwCoOzEcH13I43GhZuF/V6YbBcLt0UcEI0DC+VR
vP1sIFXj/BzQkITgzE9q067vRtgYVb85CtfESvSbLdci8noPz076wuaiRme8qzHM
SovvAcq6QGPKaB7K7veKAUW7riOaXHRzR6WAxE2t4WlZDmT/9liLPlxT38Mbl2LE
mVRPNvb1IUyWY5SoE4Dl/9ZNMlIReMrT/XVD/Udt5zOlKxica2wSHPIRyBDm5ah9
AgMBAAGgADANBgkqhkiG9w0BAQsFAAOCAgEAAkqLZQQGf8cHPqX+MWmMu42sHETv
CSqRvKM1oLcli4OCPF15axLNUAXg7+wSPOLfUkznkqukSs+ZZKoKex232ZesrDRn
IG1kkVrYRWAO6kgHHTnQJx0HOawny1OObfIlkbq/PSiprlPK5OfjyTgjK4oIDqIy
50Vifqv2akgW4/HirgUe54dILuXRlntFJtDXyanMHcRhg/Vy+I7hfIbimuBoIWuF
Z/ULNcj25+/m0VjAYNJ4gkV/TgIcWhmRLvq7AFeFo3tmEsmrbnXJnBnt1RCpAOY4
CF3T5etAsG+6JfQ/erY3Kh6sGK5XOvLSQ6SautW8DzSGCV8XKv9jQYlbM/4c3HwX
4vzIxYueW+u2MlfJZcYfkr8RK9bmk4mJCa63AK3VgRtQK21IJqNOR9lgiP202b+T
9o8CmT+rxAnEZHIr9j2nDjPlaR63lAWpSKsS/HxXr6wh2JS/34+YuhbvZlSrxYoR
D8Ta3fZYkIX7aCEziSNqRgZgz+VGroxrQCjdvTYRzr2G6LUVrr0D4dUJnBt1DhZO
klV+pv2tFl5q9szTuu0dkLNyPYFOTjCTD3GxpsuMwmONMAzsMUT+ouLVoklmXxim
Ah3ZrRv4O/hnjRZM0+tV498b4G8ZZmyp80K1CTQwLJNewpk9n2I2K7RVGFtyXa9M
irfOVbUQKaBTrqg=
-----END CERTIFICATE REQUEST-----
If my goal was only to verify integrity of a PEM file on two machines I could just use e.g. sha256sum csr.pem value but I'd like to get the same fingerprint as Puppet does
The general notion of the fingerprint/thumbprint of a certificate is a digest of the DER-encoded (binary) representation of the certificate. You can do this with the openssl x509 command directly... or indirectly:
$ openssl x509 -in test.cer -noout -sha256 -fingerprint
SHA256 Fingerprint=3E:A9:CB:54:36:DB:CF:23:50:D1:6B:D8:06:25:DC:0E:37:23:3E:A7:50:A5:D1:F3:05:0F:26:33:4E:F8:66:7C
$ openssl x509 -in test.cer -outform der | sha256sum
3ea9cb5436dbcf2350d16bd80625dc0e37233ea750a5d1f3050f26334ef8667c -
So the algorithm shouldn't require any private keys on input.
That is correct.
One of my failed attempts:
testbox:~# openssl x509 -fingerprint -in /etc/puppetlabs/puppet/ssl/certificate_requests/testbox.pem
Because the fingerprint/thumbprint is the digest of the signed certificate, it cannot be determined from the request. (The certificate has its validity information, the CA identifier, and the CA's signature... and probably extensions not present in the request.)
If you're trying to match a certificate to a certificate request, the only thing they're really guaranteed to have in common is the public key. If the -pubkey outputs match they're the same.
$ openssl req -in test.csr -pubkey -noout
-----BEGIN PUBLIC KEY-----
MIIBJDANBgkqhkiG9w0BAQEFAAOCAREAMIIBDAKCAQEAr4HBy9ggP2JKU57WYIF1
NyOTooN9SJDkihne02lzEVYglo1r4NPao4qnd74C7gtrk7ck6NzBK2MrT6gLvJJb
zmJPTKfMYGMGs5QD4oyTLSTdVG/+TvajfxB3CyIV6oy7W/Qn6MTYm3nrM4N1EAxf
g+Vd6bRGbd++7kJTmu8z7xh7d2DDsaGyEDwtgURWSgwQOaCchc9rWXTrUW/I1mI8
lK46WguztMeSlX1DI5FWbPPipSr7DBQrngaBuJcmca8rgt05Cjm5Oc9xlWhofkmQ
pjBQyndo3NazeIQvGP2x9tn/CWuve+uY3Pkw1m/P1QP1jUG/9GIS4k46/EXqQr2I
RwIFAgAABEE=
-----END PUBLIC KEY-----
$ openssl x509 -in test.cer -pubkey -noout
-----BEGIN PUBLIC KEY-----
MIIBJDANBgkqhkiG9w0BAQEFAAOCAREAMIIBDAKCAQEAr4HBy9ggP2JKU57WYIF1
NyOTooN9SJDkihne02lzEVYglo1r4NPao4qnd74C7gtrk7ck6NzBK2MrT6gLvJJb
zmJPTKfMYGMGs5QD4oyTLSTdVG/+TvajfxB3CyIV6oy7W/Qn6MTYm3nrM4N1EAxf
g+Vd6bRGbd++7kJTmu8z7xh7d2DDsaGyEDwtgURWSgwQOaCchc9rWXTrUW/I1mI8
lK46WguztMeSlX1DI5FWbPPipSr7DBQrngaBuJcmca8rgt05Cjm5Oc9xlWhofkmQ
pjBQyndo3NazeIQvGP2x9tn/CWuve+uY3Pkw1m/P1QP1jUG/9GIS4k46/EXqQr2I
RwIFAgAABEE=
-----END PUBLIC KEY-----
While I don't have an example offhand, just because they don't match doesn't mean they're different. This is because some algorithms, such as RSA, there are multiple different legal encodings for the key in SubjectPublicKeyInfo and the CA could re-normalize when signing the certificate.
For RSA you could open it with the openssl rsa command and then let OpenSSL re-normalize it (when writing it back out it won't remember which of the two representations were used)
$ openssl req -in test.csr -pubkey -noout | openssl rsa -pubin -outform der | sha256sum
writing RSA key
3305c9f5c37cb13c152d087eea65ce1af3f0f846b309cb0426f1f42ae5fcbae0 -
$ openssl x509 -in test.cer -pubkey -noout | openssl rsa -pubin -outform der | sha256sum
writing RSA key
3305c9f5c37cb13c152d087eea65ce1af3f0f846b309cb0426f1f42ae5fcbae0 -
IMHO, the answer of bartonjs didn't really answer woky's original question:
I've a certificate request (see bottom) of which I'd like get fingerprint preferably from command-line (Unix). [...] I'd like to get the same fingerprint as Puppet does
So the question was, how to get the same fingerprint of the CSR as puppet does internally.
This command should do the "magic" generating the same fingerprint.
openssl req -in /etc/puppetlabs/puppet/ssl/certificate_requests/testbox.pem -outform der | sha256sum | awk '{ print $1 }' | sed 's/\(..\)/\1:/g; s/:$//; s/./\U&/g;'
awk limits output to the sha256 string and sed re-formats the string (insert colons, all letters capital, remove ending colon). This will give you a representation of the CSR fingerprint how puppet outputs it.
Note: I haven't been able to generate the same fingerprint as woky provided in his initial question using his CSR. But I'm able to reconstruct a correct fingerprint with any CSR I generate my self, so I'd guess woky's CSR doesn't match the fingerprint provided in the question.
This is an modification of lars answer:
openssl req -in ./kontrollant.ca.csr.pem -outform DER|openssl dgst -sha256 -c
Though this gives the checksum in lower case, so awk or tr is possibilities
openssl req -in ./kontrollant.ca.csr.pem -outform DER|openssl dgst -sha256 -c|tr '[:lower:]' '[:upper:]'
Would be how i now would do this (i use the '-c' argument to openssl dgst's sha256)
Another method could be:
openssl req -in ./kontrollant.ca.csr.pem -outform DER|openssl dgst -sha256|awk '{ gsub(/../,"&:", $2); gsub(/:$/,"", $2); print upper($2) }'

Invalid CA certificate with self signed certificate chain

I have a self signed certificate chain with these commands and configured them on an Apache server
But when i try openssl s_client -showcerts -servername server -connect my-host.local:443 -CAfile all.crt
I get an error from openssl Verify return code: 24 (invalid CA certificate)
Is there something wrong with the commands used to generate the certificates or with the configuration files?
commands used to create certificate chain
# self signed root cert
openssl genrsa -aes256 -out ca.key 4096
openssl req -new -x509 -days 3000 -key ca.key -out ca.crt -config ca.conf
# intermediate cert signed with the root cert
openssl genrsa -aes256 -out int.key 4096
openssl req -new -key int.key -out int.csr -config int.conf
openssl x509 -req -days 3000 -in int.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out int.crt
# leaf cert signed with the intermediate cert
openssl genrsa -aes256 -out leaf.key 4096
openssl req -new -key leaf.key -out leaf.csr -config leaf.conf
openssl x509 -req -days 3000 -in leaf.csr -CA int.crt -CAkey int.key -set_serial 01 -out leaf.crt
cat ca.crt int.crt leaf.crt > all.crt
These are the config files I have used
ca.conf
[ req ]
distinguished_name = req_distinguished_name
x509_extensions = v3_ca
dirstring_type = nobmp
[ req_distinguished_name ]
commonName = Common Name (eg, YOUR name)
commonName_default = root
[ v3_ca ]
keyUsage=critical, keyCertSign
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer:always
basicConstraints=critical,CA:TRUE,pathlen:1
extendedKeyUsage=serverAuth
int.conf
[ req ]
distinguished_name = req_distinguished_name
x509_extensions = ext
[ req_distinguished_name ]
commonName = Common Name (eg, YOUR name)
commonName_default = int
[ ext ]
keyUsage=critical, keyCertSign
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer:always
basicConstraints=CA:TRUE,pathlen:0
extendedKeyUsage=serverAuth
leaf.conf
[ req ]
distinguished_name = req_distinguished_name
dirstring_type = nobmp
[ req_distinguished_name ]
commonName = Common Name (eg, YOUR name)
commonName_default = leaf
A CA root certificate has to be marked as belonging to a CA:
A CA certificate must include the basicConstraints value with the CA
field set to TRUE. An end user certificate must either set CA to FALSE
or exclude the extension entirely. Some software may require the
inclusion of basicConstraints with CA set to FALSE for end entity
certificates.
This is done through the basic constraints standard extension. To check whether your root cert has the CA attribute set, run openssl x509 -text -noout -in ca.crt and look for CA:True in the output. Note that OpenSSL will actually let you sign other certs with a non-CA root cert (or at least used to) but verification of such certs will fail (because the CA check will fail).
With your config file, simply including -extensions v3_ca in the command to generate the root cert should suffice:
openssl req -new -x509 -extensions v3_ca -days 3000 -key ca.key -out ca.crt -config ca.conf -extfile ca.conf

Add CRL (certificate revocating list) url to certificates

I am generating the root CA using the commands below:
openssl genrsa -aes256 -out ca.key.pem -passout pass:KeyPassword 4096
openssl req -key ca.key.pem -passin pass:Password -new -x509 -days 365 -sha256 -out ca.root.pem
and then I'm creating signed user certificates (without using intermediate certificates) using the commands below:
1) Generate a key for user
openssl req -newkey rsa:2048 -nodes -keyout keyname.pem -days 365
2) Create a CSR
openssl req -out keyname.csr -key keyname.pem -new -days 365
3) Signing the key with root cert
openssl ca -batch -create_serial -config openssl.cnf -cert ca.root.pem -keyfile ca.key.pem -passin pass:KeyFinalPassword -in keyname.csr -out certname.pem
4) Generate .p12 file
openssl pkcs12 -name username -inkey keyname.pem -in certname.pem -export -out username.p12 -password pass:password
Note - I've added crlDistributionPoints = URI:http://localhost:8000/crl/distripoint.crl.pem to the openssl.cnf along with below options:
# For certificate revocation lists.
# crlDistributionPoints = URI:http://HOSTNAME/crl/distripoint.crl.pem
crlDistributionPoints = URI:http://localhost:8000/crl/distripoint.crl.pem
crlnumber = $dir/config/crl/crlnumber
crl = $dir/config/crl/ca.crl.pem
crl_extensions = crl_ext
default_crl_days = 60
Note- I generated distribution.crl.pem using this tutorial
The crlDistributionPoints parameter must be added to the x509_extensions section of the CA you are using. (In your example, it looks like you have added this parameter to the CA section itself.)
openssl ca using the openssl.cnf with these lines adds the CRL Distribution Points extension to the issued certificate:
[ ca ]
default_ca = CA_default
[ CA_default ]
(...other parameters...)
x509_extensions = added-extensions
[ added-extensions ]
crlDistributionPoints = URI:http://localhost:8000/crl/distripoint.crl.pem
You might want to use a custom openssl.cnf instead of the default one for req and ca commands; the default contains many example entries which may not do what you want. Here are examples of minimal openssl.cnf.
(Side note: your last command generating .p12 file is not relevant to the question; it only packs already created certificates in another format.)

Self signed SSL certificate for localhost with Apache

I created a self signed SSL certificate with Open SSL and I need a key.pem and a cert.pem file...
Is it true that my server.crt = cert.pem (Certificate) , server.csr = csr.pem (Certificate request), server.key = key.pem (RSA) ? Can I just rename those files or is there a way to convert them ?
.PEM = The PEM extension is used for different types of X.509v3 files which contain ASCII (Base64) data prefixed with a “—– BEGIN …” line.
.CRT = The CRT extension is used for certificates. The certificates may be encoded as ASCII PEM. The CER and CRT extensions are nearly synonymous.
CER = alternate form of .crt (Microsoft Convention) You can use MS to convert .crt to .cer (.both DER encoded .cer, or base64[PEM] encoded .cer).
.KEY = The KEY extension is used both for public and private keys. The keys may be encoded as ASCII PEM.
The only time CRT and CER can safely be interchanged is when the encoding type can be identical. (ie PEM encoded CRT = PEM encoded CER).
I used following command to generate .pem file,
1)Generate a CA
/usr/bin/openssl req -out ca.pem -new -x509 -days 1025
This command generates CA file "ca.pem" and CA key "privkey.pem".
2)Generate server certificate/key pair
/usr/bin/openssl genrsa -out server_key.pem 1024
3)Generate server cert request
/usr/bin/openssl req -key server_key.pem -new -out server.req
4)command to generate generate .srl file
openssl x509 -req -in sguild.req -CA CA.pem -CAkey privkey.pem -CAcreateserial -out sguild.pem
5)command to generate server cert .pem
/usr/bin/openssl x509 -req -in server.req -CA ca.pem -CAkey privkey.pem -CAserial file.srl -out server_cert.pem -days 730
But I need
RootCA.pem
server.crt
server.key
so I just rename
ca.pem (generated from above command) to RootCA.pem
server_cert.pem (generated from above command) to server.crt
server_key.pem (generated from above command) to key.pem
and it works for me !!

Digital signature for a file using openssl

Is there a way to digitally sign a x509 certificate or any document using openssl?
To Generate Private Key
openssl genrsa -out privatekey.pem 2048
To Sign
openssl dgst -sha256 -sign privatekey.pem -out data.txt.signature data.txt
To Generate The Public Key
dgst -verify requires the public key
openssl rsa -in privatekey.pem -outform PEM -pubout -out publickey.pem
To Verify
openssl dgst -sha256 -verify publickey.pem -signature data.txt.signature data.txt
In case of success: prints "Verified OK", return code 0
In case of failure: prints "Verification Failure", return code 1
Yes, the dgst and rsautl component of OpenSSL can be used to compute a signature given an RSA key pair.
Signing:
openssl dgst -sha256 data.txt > hash
openssl rsautl -sign -inkey privatekey.pem -keyform PEM -in hash >signature
Verifying just the signature:
openssl rsautl -verify -inkey publickey.pem -pubin -keyform PEM -in signature
Update: Capturing Reto's comments from below because this is an important nuance. Presumably if you are going to the trouble to verify, you want to know the signature was produced on the plaintext to which it is attached:
This might sound obvious for some but: Be aware, rsautl verify just decrypts the file signature. The output of this call is guaranteed to be produced by the owner of the private key, but beside that nothing else is being checked. So to actually verify the consistency of data.txt you have to regenerate the digest and then compare it against the output of openssl rsautl -verify.
Verifying that the owner of the private key does vouch for data.txt:
openssl dgst -sha256 -verify publickey.pem -signature signature data.txt
For this operation, openssl requires the public key, the signature, and the message.
To digitally sign document in openssl it will work
For this first your certificate should be trusted
it would be look like this
-----BEGIN TRUSTED CERTIFICATE-----
MIIDbjCCAlYCCQCOyunl25ProDANBgkqhkiG9w0BAQUFADB5MQswCQYDVQQGEwJJ
...
-----END TRUSTED CERTIFICATE-----
Then use following command
smime -sign -signer certificate.pem -inkey private.key -in test.txt \
-out test1.txt -from ashish -to singhal