Hello,

I'm running the latest snapshot and I've found that I cannot create
certificates with ikectl. It fails due to the fact that the request
contains an invalid subjectAltName of only 'IP:' or 'DNS:'. In turn this
is due to the fact that in the OpenSSL config file the variable names
are 'IP:$ENV::CERTIP' and 'DNS:$ENV::CERTFQDN' but in ikeca.c they
appear as only '$ENV::CERTIP' and '$ENV::CERTFQDN'.

I don't know exactly the last working version but I think that this
issue was introduced in rev 1.41 .

With the patch below creating certificates works again. If the correct
string is built in ca_request() (prefixed with 'IP:' or 'DNS:') then it
must not be deallocated at the return of ca_request(). So I thought it's
better to change ca_setenv() to make sure that any strings it puts in
ca_env will not be deallocated too soon. But I didn't want to leave any
allocations not freed so this is the reason for also changing
ca_crlenv(). Any memory leak is irrelevant since ikectl exits
immediately but in the interest of correctness ca_crlenv() should be
called if any ca_setenv() is present in the code path. If this is not
the best way to handle this situation please let me know and I can try
to redo the patch in a different manner.

Best regards,
Andrei.

IKECTL tests with the latest snapshot version:
======================================================================
root@server1 ~ $ sysctl kern.version
kern.version=OpenBSD 6.1-current (GENERIC.MP) #4: Mon Aug 14 18:51:58 MDT 2017
    [email protected]:/usr/src/sys/arch/amd64/compile/GENERIC.MP

root@server1 ~ $ ls -lsah /usr/sbin/ikectl
104 -r-xr-xr-x  1 root  bin  50.3K Aug 15 03:42 /usr/sbin/ikectl

root@server1 ~ $ ikectl ca test-vpn create
CA passphrase:
Retype CA passphrase:
Generating RSA private key, 2048 bit long modulus
.............................................................................................................................................................+++
.+++
e is 65537 (0x10001)
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) [DE]:
State or Province Name (full name) [Lower Saxony]:
Locality Name (eg, city) [Hanover]:
Organization Name (eg, company) [OpenBSD]:
Organizational Unit Name (eg, section) [iked]:
Common Name (eg, fully qualified host name) [VPN CA]:
Email Address [[email protected]]:
Signature ok
subject=/C=DE/ST=Lower Saxony/L=Hanover/O=OpenBSD/OU=iked/CN=VPN 
CA/[email protected]
Getting Private key
Using configuration from /etc/ssl/test-vpn/ca-revoke-ssl.cnf

root@server1 ~ $ ikectl ca test-vpn certificate 10.1.2.3 create
Generating RSA private key, 2048 bit long modulus
..+++
.....+++
e is 65537 (0x10001)
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) [DE]:
State or Province Name (full name) [Lower Saxony]:
Locality Name (eg, city) [Hanover]:
Organization Name (eg, company) [OpenBSD]:
Organizational Unit Name (eg, section) [iked]:
Common Name (eg, fully qualified host name) [10.1.2.3]:
Email Address [[email protected]]:
Using configuration from /etc/ssl/test-vpn/10.1.2.3-ssl.cnf
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
countryName           :PRINTABLE:'DE'
stateOrProvinceName   :ASN.1 12:'Lower Saxony'
localityName          :ASN.1 12:'Hanover'
organizationName      :ASN.1 12:'OpenBSD'
organizationalUnitName:ASN.1 12:'iked'
commonName            :ASN.1 12:'10.1.2.3'
emailAddress          :IA5STRING:'[email protected]'
ERROR: adding extensions in section x509v3_IPAddr
13531723566432:error:22FFF06D:X509 V3 routines:func(4095):invalid null 
value:/usr/src/lib/libcrypto/x509v3/v3_utl.c:355:
13531723566432:error:22FFF069:X509 V3 routines:func(4095):invalid extension 
string:/usr/src/lib/libcrypto/x509v3/v3_conf.c:143:name=subjectAltName,section=IP:
13531723566432:error:22FFF080:X509 V3 routines:func(4095):error in 
extension:/usr/src/lib/libcrypto/x509v3/v3_conf.c:96:name=subjectAltName, 
value=IP:

root@server1 ~ $ ikectl ca test-vpn certificate test-client.test-vpn.net create
Generating RSA private key, 2048 bit long modulus
.................................+++
....................+++
e is 65537 (0x10001)
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) [DE]:
State or Province Name (full name) [Lower Saxony]:
Locality Name (eg, city) [Hanover]:
Organization Name (eg, company) [OpenBSD]:
Organizational Unit Name (eg, section) [iked]:
Common Name (eg, fully qualified host name) [test-client.test-vpn.net]:
Email Address [[email protected]]:
Using configuration from /etc/ssl/test-vpn/test-client.test-vpn.net-ssl.cnf
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
countryName           :PRINTABLE:'DE'
stateOrProvinceName   :ASN.1 12:'Lower Saxony'
localityName          :ASN.1 12:'Hanover'
organizationName      :ASN.1 12:'OpenBSD'
organizationalUnitName:ASN.1 12:'iked'
commonName            :ASN.1 12:'test-client.test-vpn.net'
emailAddress          :IA5STRING:'[email protected]'
ERROR: adding extensions in section x509v3_FQDN
32032597429408:error:22FFF06D:X509 V3 routines:func(4095):invalid null 
value:/usr/src/lib/libcrypto/x509v3/v3_utl.c:355:
32032597429408:error:22FFF069:X509 V3 routines:func(4095):invalid extension 
string:/usr/src/lib/libcrypto/x509v3/v3_conf.c:143:name=subjectAltName,section=DNS:
32032597429408:error:22FFF080:X509 V3 routines:func(4095):error in 
extension:/usr/src/lib/libcrypto/x509v3/v3_conf.c:96:name=subjectAltName, 
value=DNS:


IKECTL tests with the proposed patch:
======================================================================
root@server1 ~ $ rm /etc/ssl/test-vpn/private/*                                 
root@server1 ~ $ rmdir /etc/ssl/test-vpn/private/                               
root@server1 ~ $ rm /etc/ssl/test-vpn/*           
root@server1 ~ $ rmdir /etc/ssl/test-vpn/         

root@server1 ~ $ /usr/src/usr.sbin/ikectl/ikectl ca test-vpn create
CA passphrase:
Retype CA passphrase:
Generating RSA private key, 2048 bit long modulus
..........................+++
....+++
e is 65537 (0x10001)
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) [DE]:
State or Province Name (full name) [Lower Saxony]:
Locality Name (eg, city) [Hanover]:
Organization Name (eg, company) [OpenBSD]:
Organizational Unit Name (eg, section) [iked]:
Common Name (eg, fully qualified host name) [VPN CA]:
Email Address [[email protected]]:
Signature ok
subject=/C=DE/ST=Lower Saxony/L=Hanover/O=OpenBSD/OU=iked/CN=VPN 
CA/[email protected]
Getting Private key
Using configuration from /etc/ssl/test-vpn/ca-revoke-ssl.cnf

root@server1 ~ $ /usr/src/usr.sbin/ikectl/ikectl ca test-vpn certificate 
10.1.2.3 create
Generating RSA private key, 2048 bit long modulus
........................................................................................................+++
.....................................................................................................+++
e is 65537 (0x10001)
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) [DE]:
State or Province Name (full name) [Lower Saxony]:
Locality Name (eg, city) [Hanover]:
Organization Name (eg, company) [OpenBSD]:
Organizational Unit Name (eg, section) [iked]:
Common Name (eg, fully qualified host name) [10.1.2.3]:
Email Address [[email protected]]:
Using configuration from /etc/ssl/test-vpn/10.1.2.3-ssl.cnf
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
countryName           :PRINTABLE:'DE'
stateOrProvinceName   :ASN.1 12:'Lower Saxony'
localityName          :ASN.1 12:'Hanover'
organizationName      :ASN.1 12:'OpenBSD'
organizationalUnitName:ASN.1 12:'iked'
commonName            :ASN.1 12:'10.1.2.3'
emailAddress          :IA5STRING:'[email protected]'
Certificate is to be certified until Aug 15 21:53:56 2018 GMT (365 days)

Write out database with 1 new entries
Data Base Updated

root@server1 ~ $ /usr/src/usr.sbin/ikectl/ikectl ca test-vpn certificate 
test-client.test-vpn.net create
Generating RSA private key, 2048 bit long modulus
.....................................................+++
............................+++
e is 65537 (0x10001)
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) [DE]:
State or Province Name (full name) [Lower Saxony]:
Locality Name (eg, city) [Hanover]:
Organization Name (eg, company) [OpenBSD]:
Organizational Unit Name (eg, section) [iked]:
Common Name (eg, fully qualified host name) [test-client.test-vpn.net]:
Email Address [[email protected]]:
Using configuration from /etc/ssl/test-vpn/test-client.test-vpn.net-ssl.cnf
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
countryName           :PRINTABLE:'DE'
stateOrProvinceName   :ASN.1 12:'Lower Saxony'
localityName          :ASN.1 12:'Hanover'
organizationName      :ASN.1 12:'OpenBSD'
organizationalUnitName:ASN.1 12:'iked'
commonName            :ASN.1 12:'test-client.test-vpn.net'
emailAddress          :IA5STRING:'[email protected]'
Certificate is to be certified until Aug 15 21:54:22 2018 GMT (365 days)

Write out database with 1 new entries
Data Base Updated

root@server1 ~ $ openssl x509 -text -in /etc/ssl/test-vpn/ca.crt                
                         
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 12210187129990035033 (0xa9734c809c1a3659)
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=DE, ST=Lower Saxony, L=Hanover, O=OpenBSD, OU=iked, CN=VPN 
CA/[email protected]
        Validity
            Not Before: Aug 15 21:53:18 2017 GMT
            Not After : Aug 15 21:53:18 2018 GMT
        Subject: C=DE, ST=Lower Saxony, L=Hanover, O=OpenBSD, OU=iked, CN=VPN 
CA/[email protected]
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:b3:9a:4a:06:ac:23:9d:ff:99:26:3f:f3:28:49:
                        < ......................... >
                    e2:f1
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Basic Constraints: critical
                CA:TRUE, pathlen:1
            X509v3 Key Usage: 
                Digital Signature, Certificate Sign, CRL Sign
    Signature Algorithm: sha256WithRSAEncryption
         43:0d:9c:01:3b:e9:2c:2f:d0:de:54:30:d7:7d:d4:bc:ef:e9:
                < ......................... >
         6d:ce:5f:71
-----BEGIN CERTIFICATE-----
< ......................... >
-----END CERTIFICATE-----

root@server1 ~ $ openssl x509 -text -in /etc/ssl/test-vpn/10.1.2.3.crt
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 1 (0x1)
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=DE, ST=Lower Saxony, L=Hanover, O=OpenBSD, OU=iked, CN=VPN 
CA/[email protected]
        Validity
            Not Before: Aug 15 21:53:56 2017 GMT
            Not After : Aug 15 21:53:56 2018 GMT
        Subject: C=DE, ST=Lower Saxony, L=Hanover, O=OpenBSD, OU=iked, 
CN=10.1.2.3/[email protected]
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:b2:86:04:4c:aa:8b:b8:1d:4b:fe:06:b9:7b:6b:
                        < ......................... >
                    13:81
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Key Usage: 
                Digital Signature, Certificate Sign, CRL Sign
            Netscape Cert Type: 
                SSL Client, SSL Server
            X509v3 Subject Alternative Name: 
                IP Address:10.1.2.3
            X509v3 Extended Key Usage: 
                TLS Web Server Authentication, TLS Web Client Authentication
    Signature Algorithm: sha256WithRSAEncryption
         aa:84:95:0e:e5:a0:a5:85:3e:65:10:a8:43:36:ea:de:53:d0:
                < ......................... >
         a7:b5:00:b0
-----BEGIN CERTIFICATE-----
< ......................... >
-----END CERTIFICATE-----

root@server1 ~ $ openssl x509 -text -in 
/etc/ssl/test-vpn/test-client.test-vpn.net.crt
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 2 (0x2)
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=DE, ST=Lower Saxony, L=Hanover, O=OpenBSD, OU=iked, CN=VPN 
CA/[email protected]
        Validity
            Not Before: Aug 15 21:54:22 2017 GMT
            Not After : Aug 15 21:54:22 2018 GMT
        Subject: C=DE, ST=Lower Saxony, L=Hanover, O=OpenBSD, OU=iked, 
CN=test-client.test-vpn.net/[email protected]
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:e0:39:71:50:3c:4d:de:45:48:62:8f:ef:b6:25:
< ......................... >
                    16:0f
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Key Usage: 
                Digital Signature, Certificate Sign, CRL Sign
            Netscape Cert Type: 
                SSL Client, SSL Server
            X509v3 Subject Alternative Name: 
                DNS:test-client.test-vpn.net
            X509v3 Extended Key Usage: 
                TLS Web Server Authentication, TLS Web Client Authentication
    Signature Algorithm: sha256WithRSAEncryption
         3d:ee:34:0d:7a:a1:58:b0:f6:72:ef:df:92:41:ed:d6:ae:21:
< ......................... >
         27:b3:11:4f
-----BEGIN CERTIFICATE-----
< ......................... >
-----END CERTIFICATE-----


Proposed patch:
======================================================================
diff --git a/usr.sbin/ikectl/ikeca.c b/usr.sbin/ikectl/ikeca.c
index 3dacac9e83e..9fce2d4f04c 100644
--- a/usr.sbin/ikectl/ikeca.c
+++ b/usr.sbin/ikectl/ikeca.c
@@ -88,8 +88,8 @@ struct {
 const char *ca_env[][2] = {
        { "$ENV::CADB", NULL },
        { "$ENV::CASERIAL", NULL },
-       { "$ENV::CERTFQDN", NULL },
-       { "$ENV::CERTIP", NULL },
+       { "DNS:$ENV::CERTFQDN", NULL },
+       { "IP:$ENV::CERTIP", NULL },
        { "$ENV::CERTPATHLEN", NULL },
        { "$ENV::CERTUSAGE", NULL },
        { "$ENV::CERT_C", NULL },
@@ -202,23 +202,27 @@ ca_request(struct ca *ca, char *keyname, int type)
 {
        char            cmd[PATH_MAX * 2];
        char            hostname[HOST_NAME_MAX+1];
-       char            name[128];
+       char            subjaltname[HOST_NAME_MAX+5];
        char            path[PATH_MAX];
 
        ca_setenv("$ENV::CERT_CN", keyname);
 
-       strlcpy(name, keyname, sizeof(name));
-
        if (type == HOST_IPADDR) {
-               ca_setenv("$ENV::CERTIP", name);
+               snprintf(subjaltname, sizeof(subjaltname), "IP:%s", keyname);
+               ca_setenv("IP:$ENV::CERTIP", subjaltname);
                ca_setenv("$ENV::REQ_EXT", "x509v3_IPAddr");
        } else if (type == HOST_FQDN) {
                if (!strcmp(keyname, "local")) {
                        if (gethostname(hostname, sizeof(hostname)))
                                err(1, "gethostname");
-                       strlcpy(name, hostname, sizeof(name));
+                       snprintf(subjaltname, sizeof(subjaltname), "DNS:%s",
+                                       hostname);
+               }
+               else {
+                       snprintf(subjaltname, sizeof(subjaltname), "DNS:%s",
+                                       keyname);
                }
-               ca_setenv("$ENV::CERTFQDN", name);
+               ca_setenv("DNS:$ENV::CERTFQDN", subjaltname);
                ca_setenv("$ENV::REQ_EXT", "x509v3_FQDN");
        } else {
                errx(1, "unknown host type %d", type);
@@ -306,6 +310,9 @@ ca_certificate(struct ca *ca, char *keyname, int type, int 
action)
        ca_request(ca, keyname, type);
        ca_sign(ca, keyname, type);
 
+       /* call ca_clrenv again to free the char*'s allocated by ca_setenv */
+       ca_clrenv();
+
        return (0);
 }
 
@@ -440,6 +447,9 @@ ca_create(struct ca *ca)
        /* Create the CRL revocation list */
        ca_revoke(ca, NULL);
 
+       /* call ca_clrenv again to free the char*'s allocated by ca_setenv */
+       ca_clrenv();
+
        return (0);
 }
 
@@ -892,6 +902,11 @@ ca_revoke(struct ca *ca, char *keyname)
            ca->passfile, ca->sslpath, ca->sslpath);
        system(cmd);
 
+       if (keyname) {
+               /* ca_revoke() called directly from ca_opt() so free char *'s */
+               ca_clrenv();
+       }
+
        return (0);
 }
 
@@ -899,20 +914,26 @@ void
 ca_clrenv(void)
 {
        int      i;
-       for (i = 0; ca_env[i][0] != NULL; i++)
+       for (i = 0; ca_env[i][0] != NULL; i++) {
+               free((char *) ca_env[i][1]);
                ca_env[i][1] = NULL;
+       }
 }
 
 void
 ca_setenv(const char *key, const char *value)
 {
        int      i;
+       char    *p = NULL;
 
        for (i = 0; ca_env[i][0] != NULL; i++) {
                if (strcmp(ca_env[i][0], key) == 0) {
                        if (ca_env[i][1] != NULL)
                                errx(1, "env %s already set: %s", key, value);
-                       ca_env[i][1] = value;
+                       p = strdup(value);
+                       if (p == NULL)
+                               err(1, NULL);
+                       ca_env[i][1] = p;
                        return;
                }
        }
diff --git a/usr.sbin/ikectl/ikeca.c b/usr.sbin/ikectl/ikeca.c
index 3dacac9e83e..9fce2d4f04c 100644
--- a/usr.sbin/ikectl/ikeca.c
+++ b/usr.sbin/ikectl/ikeca.c
@@ -88,8 +88,8 @@ struct {
 const char *ca_env[][2] = {
        { "$ENV::CADB", NULL },
        { "$ENV::CASERIAL", NULL },
-       { "$ENV::CERTFQDN", NULL },
-       { "$ENV::CERTIP", NULL },
+       { "DNS:$ENV::CERTFQDN", NULL },
+       { "IP:$ENV::CERTIP", NULL },
        { "$ENV::CERTPATHLEN", NULL },
        { "$ENV::CERTUSAGE", NULL },
        { "$ENV::CERT_C", NULL },
@@ -202,23 +202,27 @@ ca_request(struct ca *ca, char *keyname, int type)
 {
        char            cmd[PATH_MAX * 2];
        char            hostname[HOST_NAME_MAX+1];
-       char            name[128];
+       char            subjaltname[HOST_NAME_MAX+5];
        char            path[PATH_MAX];
 
        ca_setenv("$ENV::CERT_CN", keyname);
 
-       strlcpy(name, keyname, sizeof(name));
-
        if (type == HOST_IPADDR) {
-               ca_setenv("$ENV::CERTIP", name);
+               snprintf(subjaltname, sizeof(subjaltname), "IP:%s", keyname);
+               ca_setenv("IP:$ENV::CERTIP", subjaltname);
                ca_setenv("$ENV::REQ_EXT", "x509v3_IPAddr");
        } else if (type == HOST_FQDN) {
                if (!strcmp(keyname, "local")) {
                        if (gethostname(hostname, sizeof(hostname)))
                                err(1, "gethostname");
-                       strlcpy(name, hostname, sizeof(name));
+                       snprintf(subjaltname, sizeof(subjaltname), "DNS:%s",
+                                       hostname);
+               }
+               else {
+                       snprintf(subjaltname, sizeof(subjaltname), "DNS:%s",
+                                       keyname);
                }
-               ca_setenv("$ENV::CERTFQDN", name);
+               ca_setenv("DNS:$ENV::CERTFQDN", subjaltname);
                ca_setenv("$ENV::REQ_EXT", "x509v3_FQDN");
        } else {
                errx(1, "unknown host type %d", type);
@@ -306,6 +310,9 @@ ca_certificate(struct ca *ca, char *keyname, int type, int 
action)
        ca_request(ca, keyname, type);
        ca_sign(ca, keyname, type);
 
+       /* call ca_clrenv again to free the char*'s allocated by ca_setenv */
+       ca_clrenv();
+
        return (0);
 }
 
@@ -440,6 +447,9 @@ ca_create(struct ca *ca)
        /* Create the CRL revocation list */
        ca_revoke(ca, NULL);
 
+       /* call ca_clrenv again to free the char*'s allocated by ca_setenv */
+       ca_clrenv();
+
        return (0);
 }
 
@@ -892,6 +902,11 @@ ca_revoke(struct ca *ca, char *keyname)
            ca->passfile, ca->sslpath, ca->sslpath);
        system(cmd);
 
+       if (keyname) {
+               /* ca_revoke() called directly from ca_opt() so free char *'s */
+               ca_clrenv();
+       }
+
        return (0);
 }
 
@@ -899,20 +914,26 @@ void
 ca_clrenv(void)
 {
        int      i;
-       for (i = 0; ca_env[i][0] != NULL; i++)
+       for (i = 0; ca_env[i][0] != NULL; i++) {
+               free((char *) ca_env[i][1]);
                ca_env[i][1] = NULL;
+       }
 }
 
 void
 ca_setenv(const char *key, const char *value)
 {
        int      i;
+       char    *p = NULL;
 
        for (i = 0; ca_env[i][0] != NULL; i++) {
                if (strcmp(ca_env[i][0], key) == 0) {
                        if (ca_env[i][1] != NULL)
                                errx(1, "env %s already set: %s", key, value);
-                       ca_env[i][1] = value;
+                       p = strdup(value);
+                       if (p == NULL)
+                               err(1, NULL);
+                       ca_env[i][1] = p;
                        return;
                }
        }

Reply via email to