Browse code

Allow external EC key through --management-external-key

- This automatically supports EC certificates through
--management-external-cert
- EC signature request from management is prompted by
>PK_SIGN if the client supports it (or >RSA_SIGN)
Response should be of the form 'pk-sig' (or rsa-sig
by older clients) followed by DER encoded signature
as base64 terminated by 'END' on a new line.

v3: This is v2 adapted to the client_version capability
Requires pacthes 1 and 2 of the series 147:
https://patchwork.openvpn.net/project/openvpn2/list/?series=147

Signed-off-by: Selva Nair <selva.nair@gmail.com>
Acked-by: Arne Schwabe <arne@rfc2549.org>
Message-Id: <1516909513-31683-1-git-send-email-selva.nair@gmail.com>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg16365.html
Signed-off-by: Gert Doering <gert@greenie.muc.de>

Selva Nair authored on 2018/01/26 04:45:13
Showing 2 changed files
... ...
@@ -779,14 +779,14 @@ COMMAND -- rsa-sig (OpenVPN 2.3 or higher, management version <= 1)
779 779
 Provides support for external storage of the private key. Requires the
780 780
 --management-external-key option. This option can be used instead of "key"
781 781
 in client mode, and allows the client to run without the need to load the
782
-actual private key. When the SSL protocol needs to perform an RSA sign
782
+actual private key. When the SSL protocol needs to perform a sign
783 783
 operation, the data to be signed will be sent to the management interface
784 784
 via a notification as follows:
785 785
 
786 786
 >PK_SIGN:[BASE64_DATA] (if client announces support for management version > 1)
787 787
 >RSA_SIGN:[BASE64_DATA] (only older clients will be prompted like this)
788 788
 
789
-The management interface client should then create a PKCS#1 v1.5 signature of
789
+The management interface client should then create an appropriate signature of
790 790
 the (decoded) BASE64_DATA using the private key and return the SSL signature as
791 791
 follows:
792 792
 
... ...
@@ -797,8 +797,9 @@ pk-sig   (or rsa-sig)
797 797
 .
798 798
 END
799 799
 
800
-Base64 encoded output of RSA_private_encrypt() (OpenSSL) or mbedtls_pk_sign()
801
-(mbed TLS) will provide a correct signature.
800
+Base64 encoded output of RSA_private_encrypt for RSA or ECDSA_sign() for EC
801
+using OpenSSL or mbedtls_pk_sign() using mbed TLS will provide a correct
802
+signature.
802 803
 
803 804
 This capability is intended to allow the use of arbitrary cryptographic
804 805
 service providers with OpenVPN via the management interface.
... ...
@@ -1043,58 +1043,51 @@ openvpn_extkey_rsa_finish(RSA *rsa)
1043 1043
     return 1;
1044 1044
 }
1045 1045
 
1046
-/* sign arbitrary data */
1046
+/* Pass the input hash in 'dgst' to management and get the signature back.
1047
+ * On input siglen contains the capacity of the buffer 'sig'.
1048
+ * On return signature is in sig.
1049
+ * Return value is signature length or -1 on error.
1050
+ */
1047 1051
 static int
1048
-rsa_priv_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)
1052
+get_sig_from_man(const unsigned char *dgst, unsigned int dgstlen,
1053
+                 unsigned char *sig, unsigned int siglen)
1049 1054
 {
1050
-    /* optional app data in rsa->meth->app_data; */
1051 1055
     char *in_b64 = NULL;
1052 1056
     char *out_b64 = NULL;
1053
-    int ret = -1;
1054
-    int len;
1057
+    int len = -1;
1055 1058
 
1056
-    if (padding != RSA_PKCS1_PADDING)
1057
-    {
1058
-        RSAerr(RSA_F_RSA_OSSL_PRIVATE_ENCRYPT, RSA_R_UNKNOWN_PADDING_TYPE);
1059
-        goto done;
1060
-    }
1061
-
1062
-    /* convert 'from' to base64 */
1063
-    if (openvpn_base64_encode(from, flen, &in_b64) <= 0)
1064
-    {
1065
-        goto done;
1066
-    }
1067
-
1068
-    /* call MI for signature */
1069
-    if (management)
1059
+    /* convert 'dgst' to base64 */
1060
+    if (management
1061
+        && openvpn_base64_encode(dgst, dgstlen, &in_b64) > 0)
1070 1062
     {
1071 1063
         out_b64 = management_query_pk_sig(management, in_b64);
1072 1064
     }
1073
-    if (!out_b64)
1065
+    if (out_b64)
1074 1066
     {
1075
-        goto done;
1067
+        len = openvpn_base64_decode(out_b64, sig, siglen);
1076 1068
     }
1077 1069
 
1078
-    /* decode base64 signature to binary */
1079
-    len = RSA_size(rsa);
1080
-    ret = openvpn_base64_decode(out_b64, to, len);
1070
+    free(in_b64);
1071
+    free(out_b64);
1072
+    return len;
1073
+}
1081 1074
 
1082
-    /* verify length */
1083
-    if (ret != len)
1084
-    {
1085
-        ret = -1;
1086
-    }
1075
+/* sign arbitrary data */
1076
+static int
1077
+rsa_priv_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)
1078
+{
1079
+    unsigned int len = RSA_size(rsa);
1080
+    int ret = -1;
1087 1081
 
1088
-done:
1089
-    if (in_b64)
1090
-    {
1091
-        free(in_b64);
1092
-    }
1093
-    if (out_b64)
1082
+    if (padding != RSA_PKCS1_PADDING)
1094 1083
     {
1095
-        free(out_b64);
1084
+        RSAerr(RSA_F_RSA_OSSL_PRIVATE_ENCRYPT, RSA_R_UNKNOWN_PADDING_TYPE);
1085
+        return -1;
1096 1086
     }
1097
-    return ret;
1087
+
1088
+    ret = get_sig_from_man(from, flen, to, len);
1089
+
1090
+    return (ret == len)? ret : -1;
1098 1091
 }
1099 1092
 
1100 1093
 static int
... ...
@@ -1166,6 +1159,130 @@ err:
1166 1166
     return 0;
1167 1167
 }
1168 1168
 
1169
+#if OPENSSL_VERSION_NUMBER > 0x10100000L && !defined(OPENSSL_NO_EC)
1170
+
1171
+/* called when EC_KEY is destroyed */
1172
+static void
1173
+openvpn_extkey_ec_finish(EC_KEY *ec)
1174
+{
1175
+    /* release the method structure */
1176
+    const EC_KEY_METHOD *ec_meth = EC_KEY_get_method(ec);
1177
+    EC_KEY_METHOD_free((EC_KEY_METHOD *) ec_meth);
1178
+}
1179
+
1180
+/* EC_KEY_METHOD callback: sign().
1181
+ * Sign the hash using EC key and return DER encoded signature in sig,
1182
+ * its length in siglen. Return value is 1 on success, 0 on error.
1183
+ */
1184
+static int
1185
+ecdsa_sign(int type, const unsigned char *dgst, int dgstlen, unsigned char *sig,
1186
+           unsigned int *siglen, const BIGNUM *kinv, const BIGNUM *r, EC_KEY *ec)
1187
+{
1188
+    int capacity = ECDSA_size(ec);
1189
+    int len = get_sig_from_man(dgst, dgstlen, sig, capacity);
1190
+
1191
+    if (len > 0)
1192
+    {
1193
+        *siglen = len;
1194
+        return 1;
1195
+    }
1196
+    return 0;
1197
+}
1198
+
1199
+/* EC_KEY_METHOD callback: sign_setup(). We do no precomputations */
1200
+static int
1201
+ecdsa_sign_setup(EC_KEY *ec, BN_CTX *ctx_in, BIGNUM **kinvp, BIGNUM **rp)
1202
+{
1203
+    return 1;
1204
+}
1205
+
1206
+/* EC_KEY_METHOD callback: sign_sig().
1207
+ * Sign the hash and return the result as a newly allocated ECDS_SIG
1208
+ * struct or NULL on error.
1209
+ */
1210
+static ECDSA_SIG *
1211
+ecdsa_sign_sig(const unsigned char *dgst, int dgstlen, const BIGNUM *in_kinv,
1212
+               const BIGNUM *in_r, EC_KEY *ec)
1213
+{
1214
+    ECDSA_SIG *ecsig = NULL;
1215
+    unsigned int len = ECDSA_size(ec);
1216
+    struct gc_arena gc = gc_new();
1217
+
1218
+    unsigned char *buf = gc_malloc(len, false, &gc);
1219
+    if (ecdsa_sign(0, dgst, dgstlen, buf, &len, NULL, NULL, ec) != 1)
1220
+    {
1221
+        goto out;
1222
+    }
1223
+    /* const char ** should be avoided: not up to us, so we cast our way through */
1224
+    ecsig = d2i_ECDSA_SIG(NULL, (const unsigned char **)&buf, len);
1225
+
1226
+out:
1227
+    gc_free(&gc);
1228
+    return ecsig;
1229
+}
1230
+
1231
+static int
1232
+tls_ctx_use_external_ec_key(struct tls_root_ctx *ctx, EVP_PKEY *pkey)
1233
+{
1234
+    EC_KEY *ec = NULL;
1235
+    EVP_PKEY *privkey = NULL;
1236
+    EC_KEY_METHOD *ec_method;
1237
+
1238
+    ASSERT(ctx);
1239
+
1240
+    ec_method = EC_KEY_METHOD_new(EC_KEY_OpenSSL());
1241
+    if (!ec_method)
1242
+    {
1243
+        goto err;
1244
+    }
1245
+
1246
+    /* Among init methods, we only need the finish method */
1247
+    EC_KEY_METHOD_set_init(ec_method, NULL, openvpn_extkey_ec_finish, NULL, NULL, NULL, NULL);
1248
+    EC_KEY_METHOD_set_sign(ec_method, ecdsa_sign, ecdsa_sign_setup, ecdsa_sign_sig);
1249
+
1250
+    ec = EC_KEY_dup(EVP_PKEY_get0_EC_KEY(pkey));
1251
+    if (!ec)
1252
+    {
1253
+        EC_KEY_METHOD_free(ec_method);
1254
+        goto err;
1255
+    }
1256
+    if (!EC_KEY_set_method(ec, ec_method))
1257
+    {
1258
+        EC_KEY_METHOD_free(ec_method);
1259
+        goto err;
1260
+    }
1261
+    /* from this point ec_method will get freed when ec is freed */
1262
+
1263
+    privkey = EVP_PKEY_new();
1264
+    if (!EVP_PKEY_assign_EC_KEY(privkey, ec))
1265
+    {
1266
+        goto err;
1267
+    }
1268
+    /* from this point ec will get freed when privkey is freed */
1269
+
1270
+    if (!SSL_CTX_use_PrivateKey(ctx->ctx, privkey))
1271
+    {
1272
+        ec = NULL; /* avoid double freeing it below */
1273
+        goto err;
1274
+    }
1275
+
1276
+    EVP_PKEY_free(privkey); /* this will down ref privkey and ec */
1277
+    return 1;
1278
+
1279
+err:
1280
+    /* Reach here only when ec and privkey can be independenly freed */
1281
+    if (privkey)
1282
+    {
1283
+        EVP_PKEY_free(privkey);
1284
+    }
1285
+    if(ec)
1286
+    {
1287
+        EC_KEY_free(ec);
1288
+    }
1289
+    return 0;
1290
+}
1291
+#endif /* OPENSSL_VERSION_NUMBER > 1.1.0 dev */
1292
+
1169 1293
 int
1170 1294
 tls_ctx_use_external_private_key(struct tls_root_ctx *ctx,
1171 1295
                                  const char *cert_file, const char *cert_file_inline)
... ...
@@ -1183,18 +1300,33 @@ tls_ctx_use_external_private_key(struct tls_root_ctx *ctx,
1183 1183
     ASSERT(pkey); /* NULL before SSL_CTX_use_certificate() is called */
1184 1184
     X509_free(cert);
1185 1185
 
1186
-    if (EVP_PKEY_get0_RSA(pkey))
1186
+    if (EVP_PKEY_id(pkey) == EVP_PKEY_RSA)
1187 1187
     {
1188 1188
         if (!tls_ctx_use_external_rsa_key(ctx, pkey))
1189 1189
         {
1190 1190
             goto err;
1191 1191
         }
1192 1192
     }
1193
+#if OPENSSL_VERSION_NUMBER > 0x10100000L && !defined(OPENSSL_NO_EC)
1194
+    else if (EVP_PKEY_id(pkey) == EVP_PKEY_EC)
1195
+    {
1196
+        if (!tls_ctx_use_external_ec_key(ctx, pkey))
1197
+        {
1198
+            goto err;
1199
+        }
1200
+    }
1201
+    else
1202
+    {
1203
+        crypto_msg(M_WARN, "management-external-key requires an RSA or EC certificate");
1204
+        goto err;
1205
+    }
1206
+#else
1193 1207
     else
1194 1208
     {
1195
-        crypto_msg(M_WARN, "management-external-key requires a RSA certificate");
1209
+        crypto_msg(M_WARN, "management-external-key requires an RSA certificate");
1196 1210
         goto err;
1197 1211
     }
1212
+#endif /* OPENSSL_VERSION_NUMBER > 1.1.0 dev */
1198 1213
     return 1;
1199 1214
 
1200 1215
 err: