Country Name field in CA generated by openssl is encoded as PRINTABLESTRING while other fields are UTF8STRING - encoding

I am generating a CA certificate with openssl version 1.0.1e with the following commands:
openssl ecparam -out ec_key.pem -name secp384r1 -genkey
openssl req -new -key ec_key.pem -x509 -nodes -days 1460 -out ec_ca_cert.pem
At the end of this process I enter DN fields as follow:
Country Name (2 letter code) [AU]:US
State or Province Name (Full Name) [Some-State]:Florida
Locality Name (eg, city)[]:Miami
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Coca Cola
Organization Unit Name (eg, section) []:Drinks
Common Name (e.g. server FQDN or YOUR name) []:Miki
Email Address []:
I convert the ec_ca_cert.pem certificate to DER format:
openssl x509 -in ec_ca_cert.pem -inform PEM -out ec_ca_cert.der -outform DER
When I edit the ec_ca_cert.der file with an HEX editor, I can clearly see that the Country field is encoded as PRINTABLESTRING (Type=0x13) while all the other fields (Locality Name, Organization Name, Organization Unit Name, Common Name) are encoded as UTF8STRING (Type=0x0c).
Is there a reason for this, or is there a problem in my process, or an openssl issue?

I got the following answer in openssl-users forum:
"countryName is ALWAYS a PrintableString, and is ALWAYS 2 characters long.
See X.520 for a normative definition, included in RFC5280 for information.
"

Related

How can I decode tbsCertificate content?

I was trying to see what's the content of a tbsCerticate.
This is what I have done:
Download a certificate from website (baidu.com) in der binary format.
Use openssl x509 -in bd.cer -inform cer -text -noout >> bd.cer.noout.txt to translate into text. Now I can see what's in the certificate
openssl asn1parse -inform der -in bd.cer > bd.cer.asn1 parse the certificate. According to rfc5280, second line is tbsCertificate content, which is 4:d=1 hl=4 l=2326 cons: SEQUENCE.
dd if=bd.cer of=bd.cer.tbsCertificate skip=4 bs=1 count=2330 to dump the bytes.
openssl x509 -in bd.cer.tbsCertificate -inform der -text -noout >> bd.cer.tbs.txt Now I want to parse it bd.cer.tbsCertificate to x509 format to see it, but it failed.
unable to load certificate
140421447947392:error:0D0680A8:asn1 encoding routines:asn1_check_tlen:wrong tag:../crypto/asn1/tasn_dec.c:1149:
140421447947392:error:0D07803A:asn1 encoding routines:asn1_item_embed_d2i:nested asn1 error:../crypto/asn1/tasn_dec.c:309:Type=X509_CINF
140421447947392:error:0D08303A:asn1 encoding routines:asn1_template_noexp_d2i:nested asn1 error:../crypto/asn1/tasn_dec.c:646:Field=cert_info, Type=X509
I want to know why I can't translate the bd.cer.tbsCertificate into x509 just like bd.cer. Do I miss something? From the error, it seems that the structure is not right.
What should I do if I want to see tbsCertificate in txt to know what exactly are encrypted. Thank you for your help!
From the error, it seems that the structure is not right.
Correct. The x509 command can only read a Certificate.
Certificate ::= SEQUENCE {
tbsCertificate TBSCertificate,
signatureAlgorithm AlgorithmIdentifier,
signatureValue BIT STRING }
TBSCertificate ::= SEQUENCE {
version [0] EXPLICIT Version DEFAULT v1,
serialNumber CertificateSerialNumber,
signature AlgorithmIdentifier,
issuer Name,
validity Validity,
subject Name,
subjectPublicKeyInfo SubjectPublicKeyInfo,
issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
-- If present, version MUST be v2 or v3
subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
-- If present, version MUST be v2 or v3
extensions [3] EXPLICIT Extensions OPTIONAL
-- If present, version MUST be v3
}
Since you've provided a TBSCertificate, not a Certificate, when it expected to see SEQUENCE, SEQUENCE, but got SEQUENCE, [0], it errored out.
Nothing in ASN.1 DER encoding says "this structure is a TBSCertificate", the structure is just a definition of the order data should be written or read. So the openssl x509 command doesn't have any inkling that you've stripped off the outer SEQUENCE (the Certificate structure). openssl asn1parse shows what the data contains. "I'm a sequence, my content is this long. I'm a sequence, my content is this long. I'm a context-specific-0, my content is this long and it is 0x02. ..."
What should I do if I want to see tbsCertificate in txt to know what exactly are encrypted.
Nothing in the certificate is encrypted.
"TBSCertificate" is "to be signed certificate". The outer structure is { "all the contents", "how did it get signed", "the signature" }. The openssl x509 command on the certificate already showed you what was in the TBSCertificate value... the version number, subject, validity, issuer, etc.

Unable to determine DKIM key length

I created a public and private key running ssh-keygen -t rsa -b 4096.
I then created a DNS entry dkim._domainkey of type TXT with this value:
v=dkim1; p=AAAAB3NzaC1yc2EAAAABIwAAAgEAvQ1GCaGx9CRKqW4wJUalTb6lGb6C1vm5iTUaus7b8EfurN8JWQouVa+n7V1YbbtAk14om7k+24i5ApbaULv8bhH5fGyano91ZQ4UpXTNxo9TrpgLntRCVQf0GlB1JNADiFMHetepf49xMDh5+NhPvgxzDBwGNqa2e4dR+SiruFKUNr5kBeLCzB9mcpzgI0jLj3PVfiB0c+SfeCcQUcGteWplurl3KLWdFAEAkTlMHPd61adt//mGRy9+XbKnVUVUNK6bn5k5pV+CSmx31pSbbFbUUjtmS4gUzPuqFDsJlVv0Sz5THNMgNiei4dSX3EqvJUmE13m+sKhImyqLoIFMTxD2Z2PxOVVqE2IqnEi9Hn+QluEiczi/g9/thWz8AnodDLlDv884LSQK7Dedie35ueyzUwgkeUsnebzSdqk1A0AqF/IcEBFiAyQyjepJ03Svv04job4cMjX90L4WoeznyCu2KTo9mTcoRRZJhLlDu0afcKavLOr6ydpJyaEsxgRzZURxFbPXUq8FGR3MbuOLszToHd6+CAOH5exRRll+Bs8O8I/dQsvJA6NqCQpynjXpNRwZ5e3RqshOR8RlZsNB4fuTk0SN2rNiozxAwQWoCl4dg+u/jfyki1GPD86qo1U1NWWXKIpXHZqYSx4FXI/CVkQ3KLI9LW1U1GxPwGVpqkU
Now when I test it using https://protodave.com/tools/dkim-key-checker/ it says:
Unable to properly parse the public key string and determine key length or the key is invalid. Tip: Make sure there aren't any special charaters or newlines pasted into your key in the TXT record.
I just copy pasted the complete key out of the file that was generated by ssh-keygen. Any tips on how I can figure out what went wrong?
I used openssl genrsa -out openssl.priv 1024 and openssl rsa -in openssl.priv -pubout >openssl.pub to generate the keys and now it works just fine.
You can and maybe should use keylength of 2048, it's in the DKIM spec.
That said, I heard of problems with mail servers hosted by AWS, insisting on 1024, but that was a few years back.
Create private key:
$openssl genrsa -out dkim_private.pem 2048
Pull out public key in der form, for encoding without LFs subsequently:
$openssl rsa -in dkim_private.pem -pubout -outform der -out dkim_public.key
Convert public key to base64 representation required:
$openssl <dkim_public.key base64 -A >p_equals
After this, the base64 encoded string in file p_equals is the string needed in your DNS TXT record (p=MI......AB ).

deleting x.509 v3 extensions from issued certificate

I need to make light weight PKC for that i want to delete x509 v3 extensions from the user certificate. May i use this openssl command to delete v3 extensions?
openssl x509 -in /usr/local/openca/var/openca/crypto/certs/E841B2655206FA6A3ADA.pem -noout -text -certopt no_extensions -out /usr/local/openca/var/openca/crypto/certs/ -out
E841B2655206FA6A3ADA_nov3ext.pem
or where should i make changes to generate x509 v1 certificate since it doesn't contain x509 extensions. could you please provide me a link for the reference.
thanks for your time.
Usually (well, virtually always really!) the signature does not just cover the distinguished name on the cert; but everything else as well (serial, expiry dates, etc).
So while it is not hard to cut down the certificate to size - it will instantly invalidate the signature by its issuer.
However - in some cases it is possible to do something else - and that is dispense/ignore the signature part of the cert completely; and just focus on the public key.
Use someting like
cat somecert.pem | openssl x509 -pubkey -nout
to get just the public key. So forego all of X509 and in essense no longer have a PKI. Just pairs of raw public keys and private keys.
Then in your application commit the fairly unforgivable gaffe of inventing your own crypto - and have the owner of that public key sign something like a NONCE with its private key; and validate the signature. E.g.
# the 'server' sends a nonce to the client
openssl rand -base64 128 > send-to-client
then on the client it is signed
cat msg-from-server | openssl pkeyutl -inkey privkey.pem -sign | base64 > send-to-server
and on the server we check this
cat msg-from-client | openssl pkeyutl -in pubkey-of-client.pem -verify
and take things form there. However unless you are a kick-ass cryptographer and protocol designer, schemes like this (and above certainly does!) are riddled with flaws and pitfalls.
But in theory it does let you use just a few 1000 bytes of RSA keys; or a few 100 bytes of Elliptic curve based keys.

OpenSSL error generating a CSR from a private key

I have got a private key that I have exported from our .p12 file. The key has been used to successfully sign the application itself.
Now I need to generate a CSR from the key. This site advises using the following command for the task:
req -out CSR.csr -key privateKey.key -new
This yields the following error:
unable to load Private Key
6420:error:0D0680A8:asn1 encoding routines:ASN1_CHECK_TLEN:wrong tag:.\crypto\asn1\tasn_dec.c:1319:
6420:error:0D06C03A:asn1 encoding routines:ASN1_D2I_EX_PRIMITIVE:nested asn1 error:.\crypto\asn1\tasn_dec.c:831:
6420:error:0D08303A:asn1 encoding routines:ASN1_TEMPLATE_NOEXP_D2I:nested asn1 error:.\crypto\asn1\tasn_dec.c:751:Field=version, Type=RSA
6420:error:04093004:rsa routines:OLD_RSA_PRIV_DECODE:RSA lib:.\crypto\rsa\rsa_ameth.c:115:
6420:error:0D0680A8:asn1 encoding routines:ASN1_CHECK_TLEN:wrong tag:.\crypto\asn1\tasn_dec.c:1319:
6420:error:0D06C03A:asn1 encoding routines:ASN1_D2I_EX_PRIMITIVE:nested asn1 error:.\crypto\asn1\tasn_dec.c:831:
6420:error:0D08303A:asn1 encoding routines:ASN1_TEMPLATE_NOEXP_D2I:nested asn1 error:.\crypto\asn1\tasn_dec.c:751:Field=version, Type=PKCS8_PRIV_KEY_INFO
6420:error:0907B00D:PEM routines:PEM_READ_BIO_PRIVATEKEY:ASN1 lib:.\crypto\pem\pem_pkey.c:132:
error in req
The error is the same as if I try
rsa -noout -text -in privateKey.key
The file does exist. What am I doing wrong and how can I fix it?
An alternative solution that did work.
1, Create a .pem file from the original .p12 (enter password when prompted)
openssl pkcs12 -in my.p12 -nocerts -out my.pem -nodes
2, Create the request from the .pem:
openssl req -new -key my.pem -out my.csr
You will be prompted to enter country, state, locality, organisation, unit and common names and your e-mail address, and extra attributes (challenge password and optional company name).
Done.
EDIT: also on CERN Certificate Authority's Prepare renewal certificate signing request(CSR) with OpenSSL.

Signing a certificate with my CA

On running:
openssl ca -in ${ALIAS}.csr -out user-cert.pem -keyfile cacert-private.pem -cert cacert.pem -passin pass:$PASSWD -config ${CONFIG}
I get:
The stateOrProvinceName field needed to be the same in the
CA certificate (Gloucestershire) and the request (Gloucestershire)
I've read the error a few times and I'm fairly sure the field is the same value in each case. I have found references to similar problems being caused by different encodings but I don't know how I should be specifying that and where.
This is the ${ALIAS}.csr:
-----BEGIN NEW CERTIFICATE REQUEST-----
MIICxzCCAa8CAQAwgYExCzAJBgNVBAYTAkdCMRgwFgYDVQQIEw9HbG91Y2VzdGVyc2hpcmUxEzAR
BgNVBAcTCkNoZWx0ZW5oYW0xHzAdBgNVBAoTFldhbnNkeWtlIEhvdXNlIExpbWl0ZWQxDjAMBgNV
BAsTBUZpemlvMRIwEAYDVQQDEwlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
AoIBAQDWvivt1JHiuaNeadOQJtxynQ4sSAR/peWgKd8g9UQgNM+H9QW4NlRE81+g63BdRqZT5YMm
J4K3upovQNlDRklevslgEYoTdQM4yBKV676Q4XDbM7Vk+rt04sqL5IgdsAUXODfMJvu81t3tOjFc
OGO7S+B+LEJ1+8qshLbuK2gBigfgcZtlbNgW6fCGik8ZsrKWl8W+NFbw1seS01INAipwCBasxaaj
/lINwWQVbQIG09+vEdwuHmmq5VIKlJqFcYNUTFBVojoJLfzyStZR2PfFUxp7R+t2YmVj6a48B7NA
lODnIlQDkAprECNMpCZoSP1QjrZgW1BgaVbT5OaWlVsPAgMBAAGgADANBgkqhkiG9w0BAQUFAAOC
AQEAvalFyJOgzmd1jcFlS5YoqiNgX1bm9nZ0/cFgj6cGL7R0Gqc9wu5QPakWRxa9c2UcI0m7p1lp
cygDvQTY23LEBhVcruymIGQG5DhDpXHeaBCbV3OWO6xowAjh+riQjvTNeVSXtP3jUNs5DaId0z+A
GXeb7dR96jhyj+soNYENoQseQLqLdAW4p0jdK1BraMJTc0ber0FBx1nOUXOEoTIJL9kL9cUWaCp3
7uYkonIPtVCCfS8KcgXxUsNMC41q/SkKDVB23PeCjnWgcyXxnSpx8n+AK7fwMgh+4TcZ5usmVujR
MNqk84hZpw8h1FIcmqRaWtaPWyv3EX8JH5LTnDe3eQ==
-----END NEW CERTIFICATE REQUEST-----
And cacert.pem:
-----BEGIN CERTIFICATE-----
MIIDQDCCAqmgAwIBAgIJAPj9mvMDl1K/MA0GCSqGSIb3DQEBBQUAMIG4MQswCQYD
VQQGEwJHQjEYMBYGA1UECAwPR2xvdWNlc3RlcnNoaXJlMRMwEQYDVQQHDApDaGVs
dGVuaGFtMR8wHQYDVQQKDBZXYW5zZHlrZSBIb3VzZSBMaW1pdGVkMQ4wDAYDVQQL
DAVGaXppbzESMBAGA1UEAwwJbG9jYWxob3N0MTUwMwYJKoZIhvcNAQkBFiZyaWNo
YXJkLm1pZHdpbnRlckB3YW5zZHlrZS1ob3VzZS5jby51azAeFw0xMTA4MDcyMTU4
NDBaFw0yMTA4MDQyMTU4NDBaMIG4MQswCQYDVQQGEwJHQjEYMBYGA1UECAwPR2xv
dWNlc3RlcnNoaXJlMRMwEQYDVQQHDApDaGVsdGVuaGFtMR8wHQYDVQQKDBZXYW5z
ZHlrZSBIb3VzZSBMaW1pdGVkMQ4wDAYDVQQLDAVGaXppbzESMBAGA1UEAwwJbG9j
YWxob3N0MTUwMwYJKoZIhvcNAQkBFiZyaWNoYXJkLm1pZHdpbnRlckB3YW5zZHlr
ZS1ob3VzZS5jby51azCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA03Y4hYdd
at3e3AB98s+E5wlxrvRL8RhJtRac0Jt0gXQy12ZYziFm3gryx0IG02srXluM+V3/
BPRRCLsnEnltfoi/fE0wM9MT0V1Ao9EXQ5t1E2rOzdoXUUdvovd6qvwG2L/DHCdL
kKjhokVR9TkFW/AWctBdWkb9qfFFTpDY4i0CAwEAAaNQME4wHQYDVR0OBBYEFHbG
d3+Lzax90slk65y1BYDgZ897MB8GA1UdIwQYMBaAFHbGd3+Lzax90slk65y1BYDg
Z897MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEArZ2yfTGJK3R+jRwP
FjaonDy1NVOt9tgjHfyh9YNQfyFSC7R987wFPcyydEqh8xg/Lb3WGwseDuzCBusw
jmVIqiUYBClHzkF3jG1766ltdlVVTOavVQgQMRBGMvpHVxcMH2RUNUyWH0XW+DH2
/uuRRpu4vX5sfEW75uEfORB9Mrg=
-----END CERTIFICATE-----
Any ideas? Thanks in advance.
You can also set the attributes as optional:
# For the CA policy
[policy_match]
countryName= optional
stateOrProvinceName= optional
organizationName= optional
organizationalUnitName= optional
commonName= supplied
emailAddress= optional
I have also run into this problem. Thanks to the replies above (mainly Francois), I discovered the source of the problem.
openssl is encoding using UTF8STRING and keytool (Java 6) is encoding with PRINTABLESTRING.
Worked around it by changing the openssl configuration so it matches keytool. In /usr/ssl/openssl.cnf change the "string_mask" setting to "pkix".
The previous posters already answered the question, but to make it easier, here is an example how to specify the encoding. Use the string_mask:
[ req ]
default_bits = 2048
default_md = rsa
prompt = no
string_mask = utf8only # <--------------
distinguished_name = req_distinguished_name
[ req_distinguished_name ]
countryName = GB
stateOrProvinceName = Gloucestershire
localityName = Cheltenham
organizationName = Wansdyke House Limited
organizationalUnitName = Fizio
commonName = localhost
As shown by :
openssl asn1parse -in req.csr
the request DN strings are encoded as PRINTABLESTRING.
openssl asn1parse -in cacert.pem
shows the CA DN strings are encoded as UTF8STRING.
For a quick'n dirty hack, I suggest you change the encoding of strings in your request by replacing the encoding type for PRINTABLESTRING (0x13) by the type for UTF8STRING (0x0c), using your favorite hex editor.
You will have to convert your request in DER before poking it.
The offset of bytes to change can be found with :
openssl asn1parse -in csr |grep PRINTABLESTRING |awk -F":" '{print $1}'
Then try to sign again.
I just ran into this problem. The root cause is a mismatch between the values of string_mask in the client's and the CA's openssl.cnf. The easy fix is to modify the client's value to match what the CA expects, then regenerate the CSR. The hard fix is to edit the CA's value and start a fresh CA.
Promoting mbrownnyc's comment to an answer, as it was useful to me and deserves more attention.
I believe /usr/ssl/openssl.cnf contains a policy called policy_anything that contains the above setup. You can use it by utilizing the policy argument as follows:
openssl ca -policy policy_anything -days 365 -out /root/ca/certs/out.pem -in certreq.csr