summary refs log tree commit diff stats
path: root/crypto/der.c
diff options
context:
space:
mode:
authorRichard Henderson <richard.henderson@linaro.org>2022-05-26 07:00:04 -0700
committerRichard Henderson <richard.henderson@linaro.org>2022-05-26 07:00:04 -0700
commit2417cbd5916d043e0c56408221fbe9935d0bc8da (patch)
treed009a0ee2069fc201b499b198f508b68900d5df4 /crypto/der.c
parent58b53669e87fed0d70903e05cd42079fbbdbc195 (diff)
parentf0cfb761bc6e590d648b759e6bdb8c946062b5f5 (diff)
downloadfocaccia-qemu-2417cbd5916d043e0c56408221fbe9935d0bc8da.tar.gz
focaccia-qemu-2417cbd5916d043e0c56408221fbe9935d0bc8da.zip
Merge tag 'ak-pull-request' of https://gitlab.com/berrange/qemu into staging
Merge asymmetric cipher crypto support

This extends the internal crypto APIs to support the use of asymmetric
ciphers.

# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEE2vOm/bJrYpEtDo4/vobrtBUQT98FAmKPWdgACgkQvobrtBUQ
# T9/dXA//XozeQbIK9y/1wb60LXiqHiHDMi8Ct1oEpNsLaL4lsp09VjtmxggqMfad
# MjxQjKdOVMVPISRnrKCJQ6qiGKQB7C/php1ZxOPdG4zgf2Ofl312GHZCLjqLkpB8
# KnhdFB31coI45EQ+agk5ZO8Baml85yY4sALLofGXV3xatJswH1HoMAmDATe5ebko
# ox7qd/S9Q4bpZA4v+8fUbvX2zI95hZta8+4d2Irx542gO8KibYKRVmffJhcKx6hy
# 4x7iTEaGQQn3DFMbVxsvb4wLwx1v8sSS6C2rHuGZY67ZzDnYhAdaHG9CaWR3uvtS
# vs7EcEWqn45SfJ/FaYUyon/btsawJrXP9NISmns4J6TYoN6sJJVxk9T9A/hlqtEE
# /iwTfp/Se+o2JDLgC+JHQz8maj4igloGNhF8+u4lXBLEpT7tlvaxhkrcPo9Um7ay
# bWpmLoxVN5vEvOnsrfLhK6LGPIzfjP4tYX0xwWy5Lm/DZ1LinJOONPXjArFr3TaQ
# rcS6L15ZaiFu9bYUyN1Uf7V7VydiVV8RlkuTqJ614gSX0v+GCMR1J+0WsQ4DtPlT
# G6WP0EnnD4Ulg9XpSMte2GXKQ0d8c7hTKr3/RW+BuvvgP5T4P7guBTRhmufRiip6
# BByKpXrQ72yGm6U+nTtEVFdUWVER31U0ufsW64hdM+LGfiG7fUE=
# =X589
# -----END PGP SIGNATURE-----
# gpg: Signature made Thu 26 May 2022 03:43:36 AM PDT
# gpg:                using RSA key DAF3A6FDB26B62912D0E8E3FBE86EBB415104FDF
# gpg: Good signature from "Daniel P. Berrange <dan@berrange.com>" [full]
# gpg:                 aka "Daniel P. Berrange <berrange@redhat.com>" [full]

* tag 'ak-pull-request' of https://gitlab.com/berrange/qemu:
  tests/crypto: Add test suite for RSA keys
  test/crypto: Add test suite for crypto akcipher
  crypto: Implement RSA algorithm by gcrypt
  crypto: Implement RSA algorithm by hogweed
  crypto: add ASN.1 DER decoder
  crypto: Introduce akcipher crypto class
  qapi: crypto-akcipher: Introduce akcipher types to qapi

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'crypto/der.c')
-rw-r--r--crypto/der.c189
1 files changed, 189 insertions, 0 deletions
diff --git a/crypto/der.c b/crypto/der.c
new file mode 100644
index 0000000000..f877390bbb
--- /dev/null
+++ b/crypto/der.c
@@ -0,0 +1,189 @@
+/*
+ * QEMU Crypto ASN.1 DER decoder
+ *
+ * Copyright (c) 2022 Bytedance
+ * Author: lei he <helei.sig11@bytedance.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "crypto/der.h"
+
+enum QCryptoDERTypeTag {
+    QCRYPTO_DER_TYPE_TAG_BOOL = 0x1,
+    QCRYPTO_DER_TYPE_TAG_INT = 0x2,
+    QCRYPTO_DER_TYPE_TAG_BIT_STR = 0x3,
+    QCRYPTO_DER_TYPE_TAG_OCT_STR = 0x4,
+    QCRYPTO_DER_TYPE_TAG_OCT_NULL = 0x5,
+    QCRYPTO_DER_TYPE_TAG_OCT_OID = 0x6,
+    QCRYPTO_DER_TYPE_TAG_SEQ = 0x10,
+    QCRYPTO_DER_TYPE_TAG_SET = 0x11,
+};
+
+#define QCRYPTO_DER_CONSTRUCTED_MASK 0x20
+#define QCRYPTO_DER_SHORT_LEN_MASK 0x80
+
+static uint8_t qcrypto_der_peek_byte(const uint8_t **data, size_t *dlen)
+{
+    return **data;
+}
+
+static void qcrypto_der_cut_nbytes(const uint8_t **data,
+                                   size_t *dlen,
+                                   size_t nbytes)
+{
+    *data += nbytes;
+    *dlen -= nbytes;
+}
+
+static uint8_t qcrypto_der_cut_byte(const uint8_t **data, size_t *dlen)
+{
+    uint8_t val = qcrypto_der_peek_byte(data, dlen);
+
+    qcrypto_der_cut_nbytes(data, dlen, 1);
+
+    return val;
+}
+
+static int qcrypto_der_invoke_callback(QCryptoDERDecodeCb cb, void *ctx,
+                                       const uint8_t *value, size_t vlen,
+                                       Error **errp)
+{
+    if (!cb) {
+        return 0;
+    }
+
+    return cb(ctx, value, vlen, errp);
+}
+
+static int qcrypto_der_extract_definite_data(const uint8_t **data, size_t *dlen,
+                                             QCryptoDERDecodeCb cb, void *ctx,
+                                             Error **errp)
+{
+    const uint8_t *value;
+    size_t vlen = 0;
+    uint8_t byte_count = qcrypto_der_cut_byte(data, dlen);
+
+    /* short format of definite-length */
+    if (!(byte_count & QCRYPTO_DER_SHORT_LEN_MASK)) {
+        if (byte_count > *dlen) {
+            error_setg(errp, "Invalid content length: %u", byte_count);
+            return -1;
+        }
+
+        value = *data;
+        vlen = byte_count;
+        qcrypto_der_cut_nbytes(data, dlen, vlen);
+
+        if (qcrypto_der_invoke_callback(cb, ctx, value, vlen, errp) != 0) {
+            return -1;
+        }
+        return vlen;
+    }
+
+    /* Ignore highest bit */
+    byte_count &= ~QCRYPTO_DER_SHORT_LEN_MASK;
+
+    /*
+     * size_t is enough to store the value of length, although the DER
+     * encoding standard supports larger length.
+     */
+    if (byte_count > sizeof(size_t)) {
+        error_setg(errp, "Invalid byte count of content length: %u",
+                   byte_count);
+        return -1;
+    }
+
+    if (byte_count > *dlen) {
+        error_setg(errp, "Invalid content length: %u", byte_count);
+        return -1;
+    }
+    while (byte_count--) {
+        vlen <<= 8;
+        vlen += qcrypto_der_cut_byte(data, dlen);
+    }
+
+    if (vlen > *dlen) {
+        error_setg(errp, "Invalid content length: %zu", vlen);
+        return -1;
+    }
+
+    value = *data;
+    qcrypto_der_cut_nbytes(data, dlen, vlen);
+
+    if (qcrypto_der_invoke_callback(cb, ctx, value, vlen, errp) != 0) {
+        return -1;
+    }
+    return vlen;
+}
+
+static int qcrypto_der_extract_data(const uint8_t **data, size_t *dlen,
+                                    QCryptoDERDecodeCb cb, void *ctx,
+                                    Error **errp)
+{
+    uint8_t val;
+    if (*dlen < 1) {
+        error_setg(errp, "Need more data");
+        return -1;
+    }
+    val = qcrypto_der_peek_byte(data, dlen);
+
+    /* must use definite length format */
+    if (val == QCRYPTO_DER_SHORT_LEN_MASK) {
+        error_setg(errp, "Only definite length format is allowed");
+        return -1;
+    }
+
+    return qcrypto_der_extract_definite_data(data, dlen, cb, ctx, errp);
+}
+
+int qcrypto_der_decode_int(const uint8_t **data, size_t *dlen,
+                           QCryptoDERDecodeCb cb, void *ctx, Error **errp)
+{
+    uint8_t tag;
+    if (*dlen < 1) {
+        error_setg(errp, "Need more data");
+        return -1;
+    }
+    tag = qcrypto_der_cut_byte(data, dlen);
+
+    /* INTEGER must encoded in primitive-form */
+    if (tag != QCRYPTO_DER_TYPE_TAG_INT) {
+        error_setg(errp, "Invalid integer type tag: %u", tag);
+        return -1;
+    }
+
+    return qcrypto_der_extract_data(data, dlen, cb, ctx, errp);
+}
+
+int qcrypto_der_decode_seq(const uint8_t **data, size_t *dlen,
+                           QCryptoDERDecodeCb cb, void *ctx, Error **errp)
+{
+    uint8_t tag;
+    if (*dlen < 1) {
+        error_setg(errp, "Need more data");
+        return -1;
+    }
+    tag = qcrypto_der_cut_byte(data, dlen);
+
+    /* SEQUENCE must use constructed form */
+    if (tag != (QCRYPTO_DER_TYPE_TAG_SEQ | QCRYPTO_DER_CONSTRUCTED_MASK)) {
+        error_setg(errp, "Invalid type sequence tag: %u", tag);
+        return -1;
+    }
+
+    return qcrypto_der_extract_data(data, dlen, cb, ctx, errp);
+}