]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
dgst commandline support for one shot signing algorithms
authorslontis <shane.lontis@oracle.com>
Mon, 10 Feb 2025 09:00:03 +0000 (20:00 +1100)
committerTomas Mraz <tomas@openssl.org>
Fri, 14 Feb 2025 17:22:01 +0000 (18:22 +0100)
Reviewed-by: Paul Dale <ppzgs1@gmail.com>
Reviewed-by: Tim Hudson <tjh@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/26697)

apps/dgst.c
doc/man1/openssl-dgst.pod.in
test/recipes/20-test_dgst.t
test/recipes/30-test_ml_dsa.t
test/testmldsa44.pem [new file with mode: 0644]
test/testmldsa44pub.pem [new file with mode: 0644]
test/testmldsa65.pem [new file with mode: 0644]
test/testmldsa65pub.pem [new file with mode: 0644]
test/testmldsa87.pem [new file with mode: 0644]
test/testmldsa87pub.pem [new file with mode: 0644]

index 50e4477aefd2a3a32ec2b120121662e02772f2ad..7992cab79626902cd20618458bd025e3beb13a80 100644 (file)
@@ -24,6 +24,9 @@
 #undef BUFSIZE
 #define BUFSIZE 1024*8
 
+static int do_fp_oneshot_sign(BIO *out, EVP_MD_CTX *ctx, BIO *in, int sep, int binout,
+                              EVP_PKEY *key, unsigned char *sigin, int siglen,
+                              const char *sig_name, const char *file);
 int do_fp(BIO *out, unsigned char *buf, BIO *bp, int sep, int binout, int xoflen,
           EVP_PKEY *key, unsigned char *sigin, int siglen,
           const char *sig_name, const char *md_name,
@@ -93,7 +96,7 @@ const OPTIONS dgst_options[] = {
 
 int dgst_main(int argc, char **argv)
 {
-    BIO *in = NULL, *inp, *bmd = NULL, *out = NULL;
+    BIO *in = NULL, *inp = NULL, *bmd = NULL, *out = NULL;
     ENGINE *e = NULL, *impl = NULL;
     EVP_PKEY *sigkey = NULL;
     STACK_OF(OPENSSL_STRING) *sigopts = NULL, *macopts = NULL;
@@ -111,6 +114,8 @@ int dgst_main(int argc, char **argv)
     unsigned char *buf = NULL, *sigbuf = NULL;
     int engine_impl = 0;
     struct doall_dgst_digests dec;
+    EVP_MD_CTX *signctx = NULL;
+    int oneshot_sign = 0;
 
     buf = app_malloc(BUFSIZE, "I/O buffer");
     md = (EVP_MD *)EVP_get_digestbyname(argv[0]);
@@ -278,8 +283,6 @@ int dgst_main(int argc, char **argv)
     }
 
     if (keyfile != NULL) {
-        int type;
-
         if (want_pub)
             sigkey = load_pubkey(keyfile, keyform, 0, NULL, e, "public key");
         else
@@ -290,14 +293,16 @@ int dgst_main(int argc, char **argv)
              */
             goto end;
         }
-        type = EVP_PKEY_get_id(sigkey);
-        if (type == EVP_PKEY_ED25519 || type == EVP_PKEY_ED448) {
-            /*
-             * We implement PureEdDSA for these which doesn't have a separate
-             * digest, and only supports one shot.
-             */
-            BIO_printf(bio_err, "Key type not supported for this operation\n");
-            goto end;
+        {
+            char def_md[80];
+
+            if (EVP_PKEY_get_default_digest_name(sigkey, def_md,
+                                                 sizeof(def_md)) == 2
+                    && strcmp(def_md, "UNDEF") == 0)
+                oneshot_sign = 1;
+            signctx = EVP_MD_CTX_new();
+            if (signctx == NULL)
+                goto end;
         }
     }
 
@@ -342,7 +347,9 @@ int dgst_main(int argc, char **argv)
         EVP_PKEY_CTX *pctx = NULL;
         int res;
 
-        if (BIO_get_md_ctx(bmd, &mctx) <= 0) {
+        if (oneshot_sign) {
+            mctx = signctx;
+        } else if (BIO_get_md_ctx(bmd, &mctx) <= 0) {
             BIO_printf(bio_err, "Error getting context\n");
             goto end;
         }
@@ -379,6 +386,11 @@ int dgst_main(int argc, char **argv)
     /* we use md as a filter, reading from 'in' */
     else {
         EVP_MD_CTX *mctx = NULL;
+
+        if (oneshot_sign) {
+            BIO_printf(bio_err, "Oneshot algorithms don't use a digest\n");
+            goto end;
+        }
         if (BIO_get_md_ctx(bmd, &mctx) <= 0) {
             BIO_printf(bio_err, "Error getting context\n");
             goto end;
@@ -407,17 +419,18 @@ int dgst_main(int argc, char **argv)
             goto end;
         }
     }
-    inp = BIO_push(bmd, in);
+    if (!oneshot_sign) {
+        inp = BIO_push(bmd, in);
 
-    if (md == NULL) {
-        EVP_MD_CTX *tctx;
+        if (md == NULL) {
+            EVP_MD_CTX *tctx;
 
-        BIO_get_md_ctx(bmd, &tctx);
-        md = EVP_MD_CTX_get1_md(tctx);
+            BIO_get_md_ctx(bmd, &tctx);
+            md = EVP_MD_CTX_get1_md(tctx);
+        }
+        if (md != NULL)
+            md_name = EVP_MD_get0_name(md);
     }
-    if (md != NULL)
-        md_name = EVP_MD_get0_name(md);
-
     if (xoflen > 0) {
         if (!EVP_MD_xof(md)) {
             BIO_printf(bio_err, "Length can only be specified for XOF\n");
@@ -436,8 +449,12 @@ int dgst_main(int argc, char **argv)
 
     if (argc == 0) {
         BIO_set_fp(in, stdin, BIO_NOCLOSE);
-        ret = do_fp(out, buf, inp, separator, out_bin, xoflen, sigkey, sigbuf,
-                    siglen, NULL, md_name, "stdin");
+        if (oneshot_sign)
+            ret = do_fp_oneshot_sign(out, signctx, in, separator, out_bin,
+                                     sigkey, sigbuf, siglen, NULL, "stdin");
+        else
+            ret = do_fp(out, buf, inp, separator, out_bin, xoflen,
+                        sigkey, sigbuf, siglen, NULL, md_name, "stdin");
     } else {
         const char *sig_name = NULL;
 
@@ -452,9 +469,16 @@ int dgst_main(int argc, char **argv)
                 ret = EXIT_FAILURE;
                 continue;
             } else {
-                if (do_fp(out, buf, inp, separator, out_bin, xoflen,
-                          sigkey, sigbuf, siglen, sig_name, md_name, argv[i]))
-                    ret = EXIT_FAILURE;
+                if (oneshot_sign) {
+                    if (do_fp_oneshot_sign(out, signctx, in, separator, out_bin,
+                                           sigkey, sigbuf, siglen, sig_name,
+                                           argv[i]))
+                        ret = EXIT_FAILURE;
+                } else {
+                    if (do_fp(out, buf, inp, separator, out_bin, xoflen,
+                              sigkey, sigbuf, siglen, sig_name, md_name, argv[i]))
+                        ret = EXIT_FAILURE;
+                }
             }
             (void)BIO_reset(bmd);
         }
@@ -468,6 +492,7 @@ int dgst_main(int argc, char **argv)
     BIO_free_all(out);
     EVP_MD_free(md);
     EVP_PKEY_free(sigkey);
+    EVP_MD_CTX_free(signctx);
     sk_OPENSSL_STRING_free(sigopts);
     sk_OPENSSL_STRING_free(macopts);
     OPENSSL_free(sigbuf);
@@ -544,6 +569,54 @@ static const char *newline_escape_filename(const char *file, int *backslash)
     return (const char*)file_cpy;
 }
 
+static void print_out(BIO *out, unsigned char *buf, size_t len,
+                      int sep, int binout,
+                      const char *sig_name, const char *md_name, const char *file)
+{
+    int i, backslash = 0;
+
+    if (binout) {
+        BIO_write(out, buf, len);
+    } else if (sep == 2) {
+        file = newline_escape_filename(file, &backslash);
+
+        if (backslash == 1)
+            BIO_puts(out, "\\");
+
+        for (i = 0; i < (int)len; i++)
+            BIO_printf(out, "%02x", buf[i]);
+
+        BIO_printf(out, " *%s\n", file);
+        OPENSSL_free((char *)file);
+    } else {
+        if (sig_name != NULL) {
+            BIO_puts(out, sig_name);
+            if (md_name != NULL)
+                BIO_printf(out, "-%s", md_name);
+            BIO_printf(out, "(%s)= ", file);
+        } else if (md_name != NULL) {
+            BIO_printf(out, "%s(%s)= ", md_name, file);
+        } else {
+            BIO_printf(out, "(%s)= ", file);
+        }
+        for (i = 0; i < (int)len; i++) {
+            if (sep && (i != 0))
+                BIO_printf(out, ":");
+            BIO_printf(out, "%02x", buf[i]);
+        }
+        BIO_printf(out, "\n");
+    }
+}
+
+static void print_verify_result(BIO *out, int i)
+{
+    if (i > 0)
+        BIO_printf(out, "Verified OK\n");
+    else if (i == 0)
+        BIO_printf(out, "Verification failure\n");
+    else
+        BIO_printf(bio_err, "Error verifying data\n");
+}
 
 int do_fp(BIO *out, unsigned char *buf, BIO *bp, int sep, int binout, int xoflen,
           EVP_PKEY *key, unsigned char *sigin, int siglen,
@@ -551,7 +624,7 @@ int do_fp(BIO *out, unsigned char *buf, BIO *bp, int sep, int binout, int xoflen
           const char *file)
 {
     size_t len = BUFSIZE;
-    int i, backslash = 0, ret = EXIT_FAILURE;
+    int i, ret = EXIT_FAILURE;
     unsigned char *allocated_buf = NULL;
 
     while (BIO_pending(bp) || !BIO_eof(bp)) {
@@ -567,16 +640,9 @@ int do_fp(BIO *out, unsigned char *buf, BIO *bp, int sep, int binout, int xoflen
         EVP_MD_CTX *ctx;
         BIO_get_md_ctx(bp, &ctx);
         i = EVP_DigestVerifyFinal(ctx, sigin, (unsigned int)siglen);
-        if (i > 0) {
-            BIO_printf(out, "Verified OK\n");
-        } else if (i == 0) {
-            BIO_printf(out, "Verification failure\n");
-            goto end;
-        } else {
-            BIO_printf(bio_err, "Error verifying data\n");
-            goto end;
-        }
-        ret = EXIT_SUCCESS;
+        print_verify_result(out, i);
+        if (i > 0)
+            ret = EXIT_SUCCESS;
         goto end;
     }
     if (key != NULL) {
@@ -617,43 +683,63 @@ int do_fp(BIO *out, unsigned char *buf, BIO *bp, int sep, int binout, int xoflen
         if ((int)len < 0)
             goto end;
     }
+    print_out(out, buf, len, sep, binout, sig_name, md_name, file);
+    ret = EXIT_SUCCESS;
+ end:
+    if (allocated_buf != NULL)
+        OPENSSL_clear_free(allocated_buf, len);
 
-    if (binout) {
-        BIO_write(out, buf, len);
-    } else if (sep == 2) {
-        file = newline_escape_filename(file, &backslash);
-
-        if (backslash == 1)
-            BIO_puts(out, "\\");
-
-        for (i = 0; i < (int)len; i++)
-            BIO_printf(out, "%02x", buf[i]);
+    return ret;
+}
 
-        BIO_printf(out, " *%s\n", file);
-        OPENSSL_free((char *)file);
-    } else {
-        if (sig_name != NULL) {
-            BIO_puts(out, sig_name);
-            if (md_name != NULL)
-                BIO_printf(out, "-%s", md_name);
-            BIO_printf(out, "(%s)= ", file);
-        } else if (md_name != NULL) {
-            BIO_printf(out, "%s(%s)= ", md_name, file);
-        } else {
-            BIO_printf(out, "(%s)= ", file);
+/*
+ * Some new algorithms only support one shot operations.
+ * For these we need to buffer all input and then do the sign on the
+ * total buffered input. These algorithms set a NULL digest name which is
+ * then used inside EVP_DigestVerify() and EVP_DigestSign().
+ */
+static int do_fp_oneshot_sign(BIO *out, EVP_MD_CTX *ctx, BIO *in, int sep, int binout,
+                              EVP_PKEY *key, unsigned char *sigin, int siglen,
+                              const char *sig_name, const char *file)
+{
+    int res, ret = EXIT_FAILURE;
+    size_t len = 0;
+    int buflen = 0;
+    int maxlen = 16 * 1024 * 1024;
+    uint8_t *buf = NULL, *sig = NULL;
+
+    buflen = bio_to_mem(&buf, maxlen, in);
+    if (buflen <= 0) {
+        BIO_printf(bio_err, "Read error in %s\n", file);
+        goto end;
+    }
+    if (sigin != NULL) {
+        res = EVP_DigestVerify(ctx, sigin, siglen, buf, buflen);
+        print_verify_result(out, res);
+        if (res > 0)
+            ret = EXIT_SUCCESS;
+        goto end;
+    }
+    if (key != NULL) {
+        if (EVP_DigestSign(ctx, NULL, &len, buf, buflen) != 1) {
+            BIO_printf(bio_err, "Error getting maximum length of signed data\n");
+            goto end;
         }
-        for (i = 0; i < (int)len; i++) {
-            if (sep && (i != 0))
-                BIO_printf(out, ":");
-            BIO_printf(out, "%02x", buf[i]);
+        sig = app_malloc(len, "Signature buffer");
+        if (EVP_DigestSign(ctx, sig, &len, buf, buflen) != 1) {
+            BIO_printf(bio_err, "Error signing data\n");
+            goto end;
         }
-        BIO_printf(out, "\n");
+        print_out(out, sig, len, sep, binout, sig_name, NULL, file);
+        ret = EXIT_SUCCESS;
+    } else {
+        BIO_printf(bio_err, "key must be set for one-shot algorithms\n");
+        goto end;
     }
 
-    ret = EXIT_SUCCESS;
  end:
-    if (allocated_buf != NULL)
-        OPENSSL_clear_free(allocated_buf, len);
+    OPENSSL_free(sig);
+    OPENSSL_clear_free(buf, buflen);
 
     return ret;
 }
index c5f6872e7d860c763f630c7adbc9eafdee4c0f04..23a1c4de1bd1ca75882612d925afe59b4905fec6 100644 (file)
@@ -116,9 +116,13 @@ Filename to output to, or standard output by default.
 
 =item B<-sign> I<filename>|I<uri>
 
-Digitally sign the digest using the given private key. Note this option
-does not support Ed25519 or Ed448 private keys. Use the L<openssl-pkeyutl(1)>
-command instead for this.
+Digitally sign the digest using the given private key.
+
+Note that for algorithms that only support one-shot signing
+(such as Ed25519, ED448, ML-DSA-44, ML-DSA-65 andML-DSA-87) the digest must not
+be set. For these algorithms the input is buffered (and not digested) before
+signing. For these algorithms, if the input is larger than 16MB an error
+will occur.
 
 =item B<-keyform> B<DER>|B<PEM>|B<P12>|B<ENGINE>
 
index 0e08d857518a629112d4d46094c61220b4e8d0b6..3221ad36f21459809511e5548111405114e7b72c 100644 (file)
@@ -17,7 +17,7 @@ use OpenSSL::Test::Utils;
 
 setup("test_dgst");
 
-plan tests => 14;
+plan tests => 17;
 
 sub tsignverify {
     my $testtext = shift;
@@ -131,8 +131,6 @@ SKIP: {
     skip "EdDSA is not supported by this OpenSSL build", 2
         if disabled("ecx");
 
-    skip "EdDSA is not supported with `dgst` CLI", 2;
-
     subtest "Ed25519 signature generation and verification with `dgst` CLI" => sub {
         tsignverify("Ed25519",
                     srctop_file("test","tested25519.pem"),
@@ -146,6 +144,27 @@ SKIP: {
     };
 }
 
+SKIP: {
+    skip "ML-DSA is not supported by this OpenSSL build", 3
+        if disabled("ml-dsa");
+
+    subtest "ML-DSA-44 signature generation and verification with `dgst` CLI" => sub {
+        tsignverify("Ml-DSA-44",
+                    srctop_file("test","testmldsa44.pem"),
+                    srctop_file("test","testmldsa44pub.pem"));
+    };
+    subtest "ML-DSA-65 signature generation and verification with `dgst` CLI" => sub {
+        tsignverify("Ml-DSA-65",
+                    srctop_file("test","testmldsa65.pem"),
+                    srctop_file("test","testmldsa65pub.pem"));
+    };
+    subtest "ML-DSA-87 signature generation and verification with `dgst` CLI" => sub {
+        tsignverify("Ml-DSA-87",
+                    srctop_file("test","testmldsa87.pem"),
+                    srctop_file("test","testmldsa87pub.pem"));
+    };
+}
+
 SKIP: {
     skip "dgst with engine is not supported by this OpenSSL build", 1
         if disabled("engine") || disabled("dynamic-engine");
index 97bd78b645206256028bc353b0d21091855cb744..1f226bfa2798c2c1c10d0ed85f9119482c59b105 100644 (file)
@@ -24,7 +24,61 @@ use lib srctop_dir('Configurations');
 use lib bldtop_dir('.');
 
 plan skip_all => 'ML-DSA is not supported in this build' if disabled('ml-dsa');
-plan tests => 2;
+plan tests => 12;
+
+require_ok(srctop_file('test','recipes','tconversion.pl'));
+
+subtest "ml-dsa-44 conversions using 'openssl pkey' -- private key" => sub {
+    tconversion( -type => "pkey",
+                 -in => srctop_file("test","testmldsa44.pem"),
+                 -prefix => "mldsa44-pkey-priv" );
+};
+subtest "ml-dsa-44 conversions using 'openssl pkey' -- pkcs8 key" => sub {
+    tconversion( -type => "pkey",
+                 -in => srctop_file("test","testmldsa44.pem"),
+                 -args => ["pkey"],
+                 -prefix => "mldsa44-pkey-pkcs8" );
+};
+subtest "ml-dsa-44 conversions using 'openssl pkey' -- pub key" => sub {
+    tconversion( -type => "pkey",
+                 -in => srctop_file("test","testmldsa44pub.pem"),
+                 -args => ["pkey", "-pubin", "-pubout"],
+                 -prefix => "mldsa44-pkey-pub" );
+};
+
+subtest "ml-dsa-65 conversions using 'openssl pkey' -- private key" => sub {
+    tconversion( -type => "pkey",
+                 -in => srctop_file("test","testmldsa65.pem"),
+                 -prefix => "mldsa65-pkey-priv");
+};
+subtest "ml-dsa-65 conversions using 'openssl pkey' -- pkcs8 key" => sub {
+    tconversion( -type => "pkey", -in => srctop_file("test","testmldsa65.pem"),
+                 -args => ["pkey"], -prefix => "mldsa65-pkey-pkcs8");
+};
+subtest "ml-dsa-65 conversions using 'openssl pkey' -- pub key" => sub {
+    tconversion( -type => "pkey",
+                 -in => srctop_file("test","testmldsa65pub.pem"),
+                 -args => ["pkey", "-pubin", "-pubout"],
+                 -prefix => "mldsa65-pkey-pub" );
+};
+
+subtest "ml-dsa-87 conversions using 'openssl pkey' -- private key" => sub {
+    tconversion( -type => "pkey",
+                 -in => srctop_file("test","testmldsa87.pem"),
+                 -prefix => "mldsa87-pkey-priv" );
+};
+subtest "ml-dsa-87 conversions using 'openssl pkey' -- pkcs8 key" => sub {
+    tconversion( -type => "pkey",
+                 -in => srctop_file("test","testmldsa87.pem"),
+                 -args => ["pkey"],
+                 -prefix => "mldsa87-pkey-pkcs8" );
+};
+subtest "ml-dsa-87 conversions using 'openssl pkey' -- pub key" => sub {
+    tconversion( -type => "pkey",
+                 -in => srctop_file("test","testmldsa87pub.pem"),
+                 -args => ["pkey", "-pubin", "-pubout"],
+                 -prefix => "mldsa87-pkey-pub" );
+};
 
 ok(run(test(["ml_dsa_test"])), "running ml_dsa_test");
 
diff --git a/test/testmldsa44.pem b/test/testmldsa44.pem
new file mode 100644 (file)
index 0000000..797613a
--- /dev/null
@@ -0,0 +1,57 @@
+-----BEGIN PRIVATE KEY-----
+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
+-----END PRIVATE KEY-----
diff --git a/test/testmldsa44pub.pem b/test/testmldsa44pub.pem
new file mode 100644 (file)
index 0000000..caf96e5
--- /dev/null
@@ -0,0 +1,30 @@
+-----BEGIN PUBLIC KEY-----
+MIIFMjALBglghkgBZQMEAxEDggUhALpx+fZOEbrrWPqcb7tuFOYfGGQ9q0lbR1Oa
+kWbKAZgTHET4JrvVbjTlXbXl4tczSF456iYPxgAMXqS6gNNFXN5TtG80SCrt/VRQ
+/C4bpPJdFfnBRCQvs5u1IocYkDDFBJjhcXt8dYsZCmdI6pqj96yq8sfLUm7XF8n3
+muuEIU+lzY3tkqDD+hVYgQ8SxwUKNncI0ZbNJOWvl0kErtjkzohy6GlrC3vKUORS
+zX0w6ppK2sAxHWcsa96EliQLB0MUY3CIlc2br8MWMtc5dkk4j9r8v30wWj3ppJXs
+p0M6j4O6DwslxBPG45yW631pGzTTfON/HurRzyF+Je807s8/fGD4S47f3ehAXU+D
+JXbGHvmOCi8o2hh3AJU5JPaGuUYUcFvPU9M/7dQ0jt3b3yi1Bl4fIHdQQ+hc+TH4
+KReTY6Gn50BKg47AAIawl2OG/mN8mCRHV+P3ad3URnRxv61nD5oF+CRu5Qp7Hq+H
+/EBpw64qogMyWBF3kvC81J4IP9G8dJar/ynMlOSGiyEhTtMWUlOZphD73UqA58gH
+FfKVeOKoS7QL3dvZ9HoRtufaEYobZY01norvVetGtTdrW2VZeZhKkivuv8WbzWAN
+UwnczXLb8Hh9uLp1e1N8Hq/VwPUOpLyVg1SeKCmkLCjKwkjJbXgSTEcVmxiu3XVK
+uhexnUMPt49jPqnSb1SpvVD42Pa3NZT4KJdufqCcU7u58RpWyVB/uJuaXrwDejcm
+epX4W41kypcZKxCmb0F7P2H+nKVxMKSP2SXq4qtVAtVxyKUZA8HTmPTB92p+EXQ5
+dq/bxpfyMJSjzXYf+Whd4y4J+zwordRTSQMAvHyJ3AF4AJYHFyKUV3XyZOGwYjvP
+RhnHEsg4dhIF2HaRt17zYBlsu56bkqDUxO1iMm5QJNd1ELjuLHQmzCLq4gncnxO9
+5r8I9ecYG9O0WUULRRpRU5pxXCHWfdMw61lw2wDZ7b+ygisDb6E7r+uG2Nx4hm4/
+jUPlPXjMpVlab6+Ia13BEvHPStz6h1gA2QtIiDr5cxb+FQaHP8FX5XDqy/0iKGjR
+QjQQGWavtr+ZQIKSU6lTraifx1a2qEn3CsuYOOafqlC7p14+icKttX6G0IirmwSi
+jmcHCRciQ+xeAAilzq8/hyL0hzAllv/XVa0bgqScNLNGlRW0aqKQzYbuOOp6m+Px
+A2EDNbUxzKMz3f4ysUUQ9LB++V/GaE6MRUqSwQ27XVnHp8Y/swX+iBln2Z5mnrYy
+hAWCVgu0A0MdQPdaSVSQhIIngpKCH06pHkLnj6SMruPINhRtz9c40RfpLpoVE30o
+6OaktGImUMtBNQTLOjNdRL7sV0bBwpSx6MuZy2CNko+M41Y2MsUh8j0TxhqPYcAd
++Mlsc2DbTzxoql0v3TQqYv80WcEWOJQhq0PoWExFiCtQ5uTpbbbwuP3okNXb+tzY
+hpC0SeZCQN2yAjdH8wg2PjAap3dXFp/GFQYo1ZILWqGrHIy/RMsA4CXXh51ytHnj
+r1MRx4VyVZDanIm5/DuEUHaVVOtE0gProruu+crSI3ARwupE7/APKZpI/+KMqT3f
+hfdmCCQu+NbMJGEKHiB4/KxPk4XDFJBeyqguVTkW2U0afB7GUqoIiXCD2qLrsXdf
+vEca4nd315BOqfG5K8rD2KMVhCYIe2RbEQjw1l/sk3icBTdDyhT9Y9BemLZS3yuc
+L/nOBfGUBwP/snP4Dg4nMuyplg2YG0z9O3u4BFs8ODBUa53Y2w0=
+-----END PUBLIC KEY-----
diff --git a/test/testmldsa65.pem b/test/testmldsa65.pem
new file mode 100644 (file)
index 0000000..a952c71
--- /dev/null
@@ -0,0 +1,88 @@
+-----BEGIN PRIVATE KEY-----
+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
+KyQlPne7UzntzuTeClPzfpyg
+-----END PRIVATE KEY-----
diff --git a/test/testmldsa65pub.pem b/test/testmldsa65pub.pem
new file mode 100644 (file)
index 0000000..16ca58d
--- /dev/null
@@ -0,0 +1,44 @@
+-----BEGIN PUBLIC KEY-----
+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
+b7MltSbq
+-----END PUBLIC KEY-----
diff --git a/test/testmldsa87.pem b/test/testmldsa87.pem
new file mode 100644 (file)
index 0000000..696bd67
--- /dev/null
@@ -0,0 +1,106 @@
+-----BEGIN PRIVATE KEY-----
+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
+wjUH4o18r/cGsoZyv2Rf878L
+-----END PRIVATE KEY-----
diff --git a/test/testmldsa87pub.pem b/test/testmldsa87pub.pem
new file mode 100644 (file)
index 0000000..d30e839
--- /dev/null
@@ -0,0 +1,57 @@
+-----BEGIN PUBLIC KEY-----
+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
+Pam8XbG1Ud+5Hps0PStXt2NDlobUow==
+-----END PUBLIC KEY-----