Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Basic support for IoT devices (--dn-mode=device) #462

Closed

Conversation

Bogdan-Stancescu-RBC
Copy link

@Bogdan-Stancescu-RBC Bogdan-Stancescu-RBC commented Oct 15, 2021

LE: Also added a couple of concrete ways to download the sources in the online docs (the second commit).

Added basic support for IoT device certificates (--dn-mode=device), which is basically the same as --dn-mode=ca_only, except it adds support for OID 2.5.4.5 (serialNumber) in the certificate's Subject. This commit should include all necessary changes for this feature, including in the inline documentation, online documentation, and appropriate vars.example changes.

Test it:

cd easyrsa3
./easyrsa init-pki
./easyrsa build-ca

# --------------------------------
# Generate full device certificate
# --------------------------------
./easyrsa --dn-mode=device build-client-full device01 nopass
# device01's Subject will have default serialNumber "My device SN"

./easyrsa --dn-mode=device --req-sn="CLI SN" build-client-full device02 nopass
# device02's Subject will have CLI-provided serialNumber "CLI SN"

export EASYRSA_REQ_SN="Env var SN"
./easyrsa --dn-mode=device build-client-full device03 nopass
# device03's Subject will have serialNumber "Env var SN", as specified in the environment variable

echo "EASYRSA_REQ_SN=\"SN from vars\"" > ./vars
./easyrsa --dn-mode=device build-client-full device04 nopass
# device04's Subject will have serialNumber "SN from vars", as specified in file vars

export EASYRSA_DN="device"
./easyrsa build-client-full device05 nopass
# device05's Subject will still contain serialNumber "SN from vars"

# ---------------------------------------
# Generate CSR on device, sign separately
# ---------------------------------------
export EASYRSA_DN="device"
./easyrsa --req-cn=dev01 --req-sn=0001 gen-req remote-device-01
./easyrsa sign client remote-device-01

@TinCanTech
Copy link
Collaborator

While I appreciate the work here, did you consider the simple approach:

build-client-full "${commonName}-${device_serial}" nopass

@Bogdan-Stancescu-RBC
Copy link
Author

As far as I can tell, your suggested solution would just include the device SN in the cert's CN. I wanted a more semantic approach, using the dedicated OID for storing the serial number. Am I making a confusion?

@TinCanTech
Copy link
Collaborator

Am I making a confusion?

No. You understood my question and gave your answer. That is why I asked.

I'm still considering this..

@TinCanTech
Copy link
Collaborator

Linking #596

@TinCanTech
Copy link
Collaborator

TinCanTech commented Jun 15, 2022

@Bogdan-Stancescu-RBC I am sorry to report this but I am really not happy to merge this pull request.

The simple fact of the matter is that EasyRSA can provide a perfectly workable solution for you as is.

In your method, you choose to abandon the extended name fields provided by --mode=org.

It is perfectly suitable to use org mode and use the organizationalUnitName as the serial-number field for your device serial number.

On top of that, EasyRSA does not need another functional --mode and the subsequent maintenance burden which that would add.

However, I am prepared to add serialNumber to org mode but not cn_only mode.

I have even prepared a patch for it.

Introduce serialNumber to REQ-DN:

diff --git a/easyrsa3/easyrsa b/easyrsa3/easyrsa
index b091b4f..1fae247 100755
--- a/easyrsa3/easyrsa
+++ b/easyrsa3/easyrsa
@@ -470,6 +470,7 @@ Distinguished Name mode:
   --req-org=NAME    : Organization
   --req-email=NAME  : Email addresses
   --req-ou=NAME     : Organizational Unit
+  --req-serial=VAL  : Alternate serial number (Not X509 serial number)
 
 Deprecated features:
 
@@ -746,6 +747,7 @@ easyrsa_openssl() {
                        -e s\`'$ENV::EASYRSA_REQ_ORG'\`\""$EASYRSA_REQ_ORG"\"\`g \
                        -e s\`'$ENV::EASYRSA_REQ_OU'\`\""$EASYRSA_REQ_OU"\"\`g \
                        -e s\`'$ENV::EASYRSA_REQ_EMAIL'\`\""$EASYRSA_REQ_EMAIL"\"\`g \
+                       -e s\`'$ENV::EASYRSA_REQ_SERIAL'\`\""$EASYRSA_REQ_SERIAL"\"\`g \
                                "$EASYRSA_SSL_CONF" > "$easyrsa_openssl_conf" || \
                                        die "easyrsa_openssl - Failed to make temporary config (1)"
 
@@ -4498,6 +4500,9 @@ while :; do
        --req-ou)
                empty_ok=1
                export EASYRSA_REQ_OU="$val" ;;
+       --req-serial)
+               empty_ok=1
+               export EASYRSA_REQ_SERIAL="$val" ;;
        --ns-cert)
                export EASYRSA_NS_SUPPORT="$val" ;;
        --ns-comment)
diff --git a/easyrsa3/openssl-easyrsa.cnf b/easyrsa3/openssl-easyrsa.cnf
index 928b195..10fb675 100644
--- a/easyrsa3/openssl-easyrsa.cnf
+++ b/easyrsa3/openssl-easyrsa.cnf
@@ -51,6 +51,7 @@ organizationalUnitName        = optional
 commonName             = supplied
 name                   = optional
 emailAddress           = optional
+serialNumber                   = optional
 
 ####################################################################
 # Easy-RSA request handling
@@ -101,6 +102,9 @@ emailAddress                        = Email Address
 emailAddress_default           = $ENV::EASYRSA_REQ_EMAIL
 emailAddress_max               = 64
 
+serialNumber                           = Device name or serial number
+serialNumber_default           = $ENV::EASYRSA_REQ_SERIAL
+
 ####################################################################
 # Easy-RSA cert extension handling

Demonstration:

tct@home:~/git/easy-rsa/test/installed$ easyrsa init-pki

WARNING!!!

You are about to remove the EASYRSA_PKI at:
* /home/tct/git/easy-rsa/test/installed/pki

and initialize a fresh PKI here.

Type the word 'yes' to continue, or any other input to abort.
  Confirm removal: yes


Notice
------
'init-pki' complete; you may now create a CA or requests.

Your newly created PKI dir is:
* /home/tct/git/easy-rsa/test/installed/pki

* IMPORTANT: Easy-RSA 'vars' file has now been moved to your PKI above.

tct@home:~/git/easy-rsa/test/installed$ easyrsa --dn-mode=org build-ca nopass
* Using Easy-RSA configuration from: /home/tct/git/easy-rsa/test/installed/pki/vars
* Using SSL: openssl OpenSSL 1.1.1f  31 Mar 2020
.......+++++
................................................................+++++
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [US]:
State or Province Name (full name) [California]:
Locality Name (eg, city) [San Francisco]:
Organization Name (eg, company) [Copyleft Certificate Co]:
Organizational Unit Name (eg, section) [My Organizational Unit]:
Common Name (eg: your user, host, or server name) [Easy-RSA CA]:
Email Address [[email protected]]:
Device name or serial number []:

Notice
------
CA creation complete and you may now import and sign cert requests.
Your new CA certificate file for publishing is at:
/home/tct/git/easy-rsa/test/installed/pki/ca.crt

tct@home:~/git/easy-rsa/test/installed$ easyrsa show-ca
* Using Easy-RSA configuration from: /home/tct/git/easy-rsa/test/installed/pki/vars
* Using SSL: openssl OpenSSL 1.1.1f  31 Mar 2020

Notice
------

Showing  details for 'ca'.

This file is stored at:
* /home/tct/git/easy-rsa/test/installed/pki/ca.crt

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            01:3a:c7:c4:35:22:49:93:ee:c4:36:ef:1b:9b:d1:43:a9:98:c7:70
        Signature Algorithm: sha256WithRSAEncryption
        Issuer:
            countryName               = US
            stateOrProvinceName       = California
            localityName              = San Francisco
            organizationName          = Copyleft Certificate Co
            organizationalUnitName    = My Organizational Unit
            commonName                = Easy-RSA CA
            emailAddress              = [email protected]
        Validity
            Not Before: Jun 15 12:40:40 2022 GMT
            Not After : Jun 12 12:40:40 2032 GMT
        Subject:
            countryName               = US
            stateOrProvinceName       = California
            localityName              = San Francisco
            organizationName          = Copyleft Certificate Co
            organizationalUnitName    = My Organizational Unit
            commonName                = Easy-RSA CA
            emailAddress              = [email protected]
        X509v3 extensions:
            X509v3 Basic Constraints: 
                CA:TRUE
            X509v3 Subject Key Identifier: 
                66:AC:2D:58:AD:7D:14:7D:62:96:EF:FC:F1:C8:AA:9C:48:1F:B3:28
            X509v3 Authority Key Identifier: 
                keyid:66:AC:2D:58:AD:7D:14:7D:62:96:EF:FC:F1:C8:AA:9C:48:1F:B3:28
                DirName:/C=US/ST=California/L=San Francisco/O=Copyleft Certificate Co/OU=My Organizational Unit/CN=Easy-RSA CA/[email protected]
                serial:01:3A:C7:C4:35:22:49:93:EE:C4:36:EF:1B:9B:D1:43:A9:98:C7:70

            X509v3 Key Usage: 
                Certificate Sign, CRL Sign

tct@home:~/git/easy-rsa/test/installed$ easyrsa --dn-mode=org build-server-full s1 nopass
* Using Easy-RSA configuration from: /home/tct/git/easy-rsa/test/installed/pki/vars
* Using SSL: openssl OpenSSL 1.1.1f  31 Mar 2020
Generating a RSA private key
...............................+++++
...........................+++++
writing new private key to '/home/tct/git/easy-rsa/test/installed/pki/21bd1201/temp.d23d7541'
-----

Notice
------
Keypair and certificate request completed. Your files are:
req: /home/tct/git/easy-rsa/test/installed/pki/reqs/s1.req
key: /home/tct/git/easy-rsa/test/installed/pki/private/s1.key

Using configuration from /home/tct/git/easy-rsa/test/installed/pki/21bd1201/temp.e00cfd6a
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
countryName           :PRINTABLE:'US'
stateOrProvinceName   :ASN.1 12:'California'
localityName          :ASN.1 12:'San Francisco'
organizationName      :ASN.1 12:'Copyleft Certificate Co'
organizationalUnitName:ASN.1 12:'My Organizational Unit'
commonName            :ASN.1 12:'s1'
emailAddress          :IA5STRING:'[email protected]'
Certificate is to be certified until Sep 17 12:41:09 2024 GMT (825 days)

Write out database with 1 new entries
Data Base Updated

Notice
------
Certificate created at: /home/tct/git/easy-rsa/test/installed/pki/issued/s1.crt


tct@home:~/git/easy-rsa/test/installed$ easyrsa show-cert s1 nopass
* Using Easy-RSA configuration from: /home/tct/git/easy-rsa/test/installed/pki/vars
* Using SSL: openssl OpenSSL 1.1.1f  31 Mar 2020

WARNING
=======
Ignoring unknown command option: 'nopass'


Notice
------
Showing cert details for: 's1'

This file is stored at:
* /home/tct/git/easy-rsa/test/installed/pki/issued/s1.crt

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            f1:e3:1b:43:fe:6c:48:f1:f5:7f:77:fa:9a:af:25:70
        Signature Algorithm: sha256WithRSAEncryption
        Issuer:
            countryName               = US
            stateOrProvinceName       = California
            localityName              = San Francisco
            organizationName          = Copyleft Certificate Co
            organizationalUnitName    = My Organizational Unit
            commonName                = Easy-RSA CA
            emailAddress              = [email protected]
        Validity
            Not Before: Jun 15 12:41:09 2022 GMT
            Not After : Sep 17 12:41:09 2024 GMT
        Subject:
            countryName               = US
            stateOrProvinceName       = California
            localityName              = San Francisco
            organizationName          = Copyleft Certificate Co
            organizationalUnitName    = My Organizational Unit
            commonName                = s1
            emailAddress              = [email protected]
        X509v3 extensions:
            X509v3 Basic Constraints: 
                CA:FALSE
            X509v3 Subject Key Identifier: 
                19:1A:86:50:F7:83:3B:0B:0B:31:02:09:31:14:A4:48:B7:FC:05:64
            X509v3 Authority Key Identifier: 
                keyid:66:AC:2D:58:AD:7D:14:7D:62:96:EF:FC:F1:C8:AA:9C:48:1F:B3:28
                DirName:/C=US/ST=California/L=San Francisco/O=Copyleft Certificate Co/OU=My Organizational Unit/CN=Easy-RSA CA/[email protected]
                serial:01:3A:C7:C4:35:22:49:93:EE:C4:36:EF:1B:9B:D1:43:A9:98:C7:70

            X509v3 Extended Key Usage: 
                TLS Web Server Authentication
            X509v3 Key Usage: 
                Digital Signature, Key Encipherment
            X509v3 Subject Alternative Name: 
                DNS:s1

tct@home:~/git/easy-rsa/test/installed$ easyrsa --dn-mode=org --req-serial=1234567890 build-client-full c1 nopass
* Using Easy-RSA configuration from: /home/tct/git/easy-rsa/test/installed/pki/vars
* Using SSL: openssl OpenSSL 1.1.1f  31 Mar 2020
Generating a RSA private key
.......+++++
..+++++
writing new private key to '/home/tct/git/easy-rsa/test/installed/pki/2e0b5f7e/temp.dfdce4c5'
-----

Notice
------
Keypair and certificate request completed. Your files are:
req: /home/tct/git/easy-rsa/test/installed/pki/reqs/c1.req
key: /home/tct/git/easy-rsa/test/installed/pki/private/c1.key

Using configuration from /home/tct/git/easy-rsa/test/installed/pki/2e0b5f7e/temp.e7997cd5
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
countryName           :PRINTABLE:'US'
stateOrProvinceName   :ASN.1 12:'California'
localityName          :ASN.1 12:'San Francisco'
organizationName      :ASN.1 12:'Copyleft Certificate Co'
organizationalUnitName:ASN.1 12:'My Organizational Unit'
commonName            :ASN.1 12:'c1'
emailAddress          :IA5STRING:'[email protected]'
serialNumber          :PRINTABLE:'1234567890'
Certificate is to be certified until Sep 17 12:42:16 2024 GMT (825 days)

Write out database with 1 new entries
Data Base Updated

Notice
------
Certificate created at: /home/tct/git/easy-rsa/test/installed/pki/issued/c1.crt

tct@home:~/git/easy-rsa/test/installed$ easyrsa show-cert c1 nopass
* Using Easy-RSA configuration from: /home/tct/git/easy-rsa/test/installed/pki/vars
* Using SSL: openssl OpenSSL 1.1.1f  31 Mar 2020

WARNING
=======
Ignoring unknown command option: 'nopass'


Notice
------
Showing cert details for: 'c1'

This file is stored at:
* /home/tct/git/easy-rsa/test/installed/pki/issued/c1.crt

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            a6:61:2f:3e:6d:17:78:bd:71:52:84:68:37:9e:13:18
        Signature Algorithm: sha256WithRSAEncryption
        Issuer:
            countryName               = US
            stateOrProvinceName       = California
            localityName              = San Francisco
            organizationName          = Copyleft Certificate Co
            organizationalUnitName    = My Organizational Unit
            commonName                = Easy-RSA CA
            emailAddress              = [email protected]
        Validity
            Not Before: Jun 15 12:42:16 2022 GMT
            Not After : Sep 17 12:42:16 2024 GMT
        Subject:
            countryName               = US
            stateOrProvinceName       = California
            localityName              = San Francisco
            organizationName          = Copyleft Certificate Co
            organizationalUnitName    = My Organizational Unit
            commonName                = c1
            emailAddress              = [email protected]
            serialNumber              = 1234567890
        X509v3 extensions:
            X509v3 Basic Constraints: 
                CA:FALSE
            X509v3 Subject Key Identifier: 
                A7:D7:55:48:D2:5D:3B:28:4B:65:C5:57:39:0D:DB:D5:28:7E:94:F4
            X509v3 Authority Key Identifier: 
                keyid:66:AC:2D:58:AD:7D:14:7D:62:96:EF:FC:F1:C8:AA:9C:48:1F:B3:28
                DirName:/C=US/ST=California/L=San Francisco/O=Copyleft Certificate Co/OU=My Organizational Unit/CN=Easy-RSA CA/[email protected]
                serial:01:3A:C7:C4:35:22:49:93:EE:C4:36:EF:1B:9B:D1:43:A9:98:C7:70

            X509v3 Extended Key Usage: 
                TLS Web Client Authentication
            X509v3 Key Usage: 
                Digital Signature

@Bogdan-Stancescu-RBC
Copy link
Author

Thank you for taking the time to investigate this and work out a solution that's convenient for everyone. I had considered the IoT devices' certificates as very lightweight, almost disposable things, but upon consideration of your proposal I realized it's actually important for them to be attached to an organization – so in the end I think your solution is actually better than mine.

Thank you again for your time and consideration!

@TinCanTech
Copy link
Collaborator

TinCanTech commented Jun 15, 2022

Thanks for your time and patience on this one. I'll get my version merged, soon.

I'll add a credit in git log for you're initial work and idea.

@TinCanTech
Copy link
Collaborator

Unfortunately, using serialNumber has unexpected side effects. (Also name)

Closing this as: Original problem solved, full solution is out-of-scope for EasyRSA, at this time. Future pull requests welcome, if they work correctly.

@TinCanTech
Copy link
Collaborator

Re-opening-as: Feature request

@TinCanTech
Copy link
Collaborator

TinCanTech commented Jun 17, 2022

@Bogdan-Stancescu-RBC I found a suitable solution to your request.

In --dn-mode=org there is now a new field 1.organizationalUnitName.

This works the same way as the normal fields in org mode and is suitable for your use of a device serial number.

If you find time to test then please let me know if/how it works for you, good feedback will expedite merging.

Thanks

@Bogdan-Stancescu-RBC
Copy link
Author

@TinCanTech I'm afraid that doesn't suit my business case. I specifically need the serialNumber OID because I genuinely need to populate the device's immutable hardware SN in that field. Using anything else than the dedicated OID would result in semantic ambiguity.

@TinCanTech
Copy link
Collaborator

@Bogdan-Stancescu-RBC I don't see how the field name used to store your device serial number makes any difference to your external requirements.

Using serialNumber in a certificate is ambiguous. Because OpenSSL treats serialNumber uniquely and applies specific behavior rules to it, which do not fit with EasyRSA functionality.

Your initial PR discarded the org mode fields, which only masked this unwanted behavior. It did not stop it.

@TinCanTech
Copy link
Collaborator

TinCanTech commented Jun 17, 2022

Now that I have a functional frame work, I can test this further and perhaps change to serialNumber. However, as the field stands now, it is multi-purpose.

@Bogdan-Stancescu-RBC
Copy link
Author

I'm very confused. I always thought OID 2.5.4.5 (part of the subject data, and distinct from the certificate SN) was meant specifically to identify the subject's (i.e. device's) serial number (not the certificate's). Why do you feel that would be ambiguous?

@Bogdan-Stancescu-RBC
Copy link
Author

Bogdan-Stancescu-RBC commented Jun 17, 2022

For clarity, my only intention ever was to be able to issue certificates for IoT devices using EasyRSA, specifically because it's a very convenient toolset. I approached this by including the device's hardware serial number in the certificate in the most standard, semantically-identifiable, non-ambiguous manner I managed to identify. I might have approached the issue completely wrongly from a maintenance perspective in the context of EasyRSA, and I might be confused about specific technical details regarding X.509 certificates, but I never had any other objective.

I'm happy with any technical solution that reaches those objectives. If we can't find one which also works with EasyRSA's maintainability/philosophical constraints I'll have to keep maintaining my own fork. Which is a PITA, and it widows the rest of the community of a functionality which I believe will gain traction as IoT devices become more mature security-wise.

Regardless, I will be forever grateful to this community (and the OpenVPN community in general) for EasyRSA; it really taught me a lot and made my life a lot easier than having to deal with all of the complexity of openssl from day 1.

@TinCanTech
Copy link
Collaborator

TinCanTech commented Jun 17, 2022

For clarity on my-side; I have not made a final decision on this and your answer above does clear up some likely misconceptions I have ..

I will spend some time digging into this further and see if a better (Industry standard) approach can be found. Thanks for your feedback and patience.

@TinCanTech
Copy link
Collaborator

Please see #599

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants