From a7aa36f2e3359a9d5cc164cc418352b629451e7c Mon Sep 17 00:00:00 2001 From: Mark Wooding Date: Wed, 10 May 2017 21:23:22 +0100 Subject: [PATCH] pub/ed25519.[ch], etc.: Implement the `context' variant from RFC8032. Add the test vectors from the RFC, and a little Makefile machinery to mix them into the main test set. --- progs/cc-sig.c | 48 +++++++++----- pub/ed25519.c | 184 ++++++++++++++++++++++++++++++++++++++++------------ pub/ed25519.h | 39 ++++++++++- pub/t/ed25519.local | 69 ++++++++++++++++++++ 4 files changed, 283 insertions(+), 57 deletions(-) diff --git a/progs/cc-sig.c b/progs/cc-sig.c index 7303c563..fb5e1c3d 100644 --- a/progs/cc-sig.c +++ b/progs/cc-sig.c @@ -577,33 +577,48 @@ static const sigops eckcdsa_vrf = { /* --- EdDSA --- */ #define EDDSAS(_) \ - _(ed25519, ED25519, "Ed25519", sha512) + _(ed25519, ed25519ctx, ED25519, "Ed25519", sha512) + +typedef struct eddsa_sigctx { + sig s; + const char *perso; +} eddsa_sigctx; static sig *eddsa_siginit(key *k, void *kd, const gchash *hc) { - sig *s = CREATE(sig); - s->h = 0; - return (s); + eddsa_sigctx *es = CREATE(eddsa_sigctx); + es->s.h = 0; + es->perso = key_getattr(0, k, "perso"); + if (es->perso && strlen(es->perso) > ED25519_MAXPERSOSZ) { + die(1, "EdDSA personalization string too long (max length %d)", + ED25519_MAXPERSOSZ); + } + return (&es->s); } -static void eddsa_sigdestroy(sig *s) { DESTROY(s); } +static void eddsa_sigdestroy(sig *s) + { eddsa_sigctx *es = (eddsa_sigctx *)s; DESTROY(es); } -#define EDDSADEF(ed, ED, name, hash) \ +#define EDDSADEF(ed, sigver, ED, name, hash) \ \ static int ed##_sigdoit(sig *s, dstr *d) \ { \ - ed##_priv *k = s->kd; \ + eddsa_sigctx *es = (eddsa_sigctx *)s; \ + ed##_priv *k = es->s.kd; \ \ dstr_ensure(d, ED##_SIGSZ); \ - ed##_sign((octet *)d->buf, k->priv.k, k->priv.sz, k->pub.k, \ - GH_DONE(s->h, 0), GH_CLASS(s->h)->hashsz); \ + sigver##_sign((octet *)d->buf, k->priv.k, k->priv.sz, k->pub.k, \ + es->perso ? 1 : -1, es->perso, \ + es->perso ? strlen(es->perso) : 0, \ + GH_DONE(es->s.h, 0), GH_CLASS(es->s.h)->hashsz); \ d->len += ED##_SIGSZ; \ return (0); \ } \ \ static const char *ed##_sigcheck(sig *s) \ { \ - ed##_priv *k = s->kd; \ + eddsa_sigctx *es = (eddsa_sigctx *)s; \ + ed##_priv *k = es->s.kd; \ \ if (k->pub.sz != ED##_PUBSZ) \ return ("incorrect " #name " public key length"); \ @@ -617,12 +632,15 @@ static void eddsa_sigdestroy(sig *s) { DESTROY(s); } \ static int ed##_vrfdoit(sig *s, dstr *d) \ { \ - ed##_pub *k = s->kd; \ + eddsa_sigctx *es = (eddsa_sigctx *)s; \ + ed##_pub *k = es->s.kd; \ \ if (d->len != ED##_SIGSZ) return (-1); \ - return (ed##_verify(k->pub.k, \ - GH_DONE(s->h, 0), GH_CLASS(s->h)->hashsz, \ - (const octet *)d->buf)); \ + return (sigver##_verify(k->pub.k, \ + es->perso ? 1 : -1, es->perso, \ + es->perso ? strlen(es->perso) : 0, \ + GH_DONE(s->h, 0), GH_CLASS(s->h)->hashsz, \ + (const octet *)d->buf)); \ } \ \ static const char *ed##_vrfcheck(sig *s) \ @@ -740,7 +758,7 @@ const struct sigtab sigtab[] = { { "kcdsa", &kcdsa_sig, &kcdsa_vrf, &has160 }, { "binkcdsa", &binkcdsa_sig, &binkcdsa_vrf, &has160 }, { "eckcdsa", &eckcdsa_sig, &eckcdsa_vrf, &has160 }, -#define EDDSATAB(ed, ED, name, hash) \ +#define EDDSATAB(ed, sigver, ED, name, hash) \ { #ed, &ed##_sig, &ed##_vrf, &hash }, EDDSAS(EDDSATAB) #undef EDDSATAB diff --git a/pub/ed25519.c b/pub/ed25519.c index c6b805c4..82099f2c 100644 --- a/pub/ed25519.c +++ b/pub/ed25519.c @@ -392,6 +392,17 @@ static void unpack_key(scaf_piece a[NPIECE], octet h1[32], if (h1) memcpy(h1, b + 32, 32); } +#define PREFIX_BUFSZ 290 +static size_t prefix(octet b[PREFIX_BUFSZ], + int phflag, const octet *p, size_t psz) +{ + if (phflag < 0) return (0); + memcpy(b, "SigEd25519 no Ed25519 collisions", 32); + b[32] = phflag; + assert(psz < ED25519_MAXPERSOSZ); b[33] = psz; memcpy(b + 34, p, psz); + return (psz + 34); +} + /*----- Main code ---------------------------------------------------------*/ /* --- @ed25519_pubkey@ --- * @@ -415,52 +426,65 @@ void ed25519_pubkey(octet K[ED25519_PUBSZ], const void *k, size_t ksz) ptencode(K, &AX, &AY, &AZ); } -/* --- @ed25519_sign@ --- * +/* --- @ed25519_sign@, @ed25519ctx_sign@ --- * * * Arguments: @octet sig[ED25519_SIGSZ]@ = where to put the signature * @const void *k@ = private key * @size_t ksz@ = length of private key * @const octet K[ED25519_PUBSZ]@ = public key + * @int phflag@ = whether the `message' has been hashed already + * @const void *p@ = personalization string + * @size_t psz@ = length of personalization string * @const void *m@ = message to sign * @size_t msz@ = length of message * * Returns: --- * * Use: Signs a message. + * + * In @ed25519ctx_sign@, if @phflag@ is @-1@ then you get plain + * old Ed25519: the personalization string pointer @p@ will be + * ignored. If @phflag > 0@ then the `message' @m@ should be a + * SHA512 hash of the actual message. */ -void ed25519_sign(octet sig[ED25519_SIGSZ], - const void *k, size_t ksz, - const octet K[ED25519_PUBSZ], - const void *m, size_t msz) +void ed25519ctx_sign(octet sig[ED25519_SIGSZ], + const void *k, size_t ksz, const octet K[ED25519_PUBSZ], + int phflag, const void *p, size_t psz, + const void *m, size_t msz) { sha512_ctx h; scaf_piece a[NPIECE], r[NPIECE], t[NPIECE], scratch[3*NPIECE + 1]; scaf_dblpiece tt[2*NPIECE]; f25519 RX, RY, RZ; - octet h1[32], b[SHA512_HASHSZ]; + octet h1[32], pb[PREFIX_BUFSZ], rb[SHA512_HASHSZ]; unsigned i; /* Get my private key. */ unpack_key(a, h1, k, ksz); + /* Determine the prefix string. */ + psz = prefix(pb, phflag, p, psz); + /* Select the nonce and the vector part. */ sha512_init(&h); + sha512_hash(&h, pb, psz); sha512_hash(&h, h1, 32); sha512_hash(&h, m, msz); - sha512_done(&h, b); - scaf_loaddbl(tt, b, 64, 2*NPIECE, PIECEWD); + sha512_done(&h, rb); + scaf_loaddbl(tt, rb, 64, 2*NPIECE, PIECEWD); scaf_reduce(r, tt, l, mu, NPIECE, PIECEWD, scratch); ptmul(&RX, &RY, &RZ, r, BX, BY, BZ); ptencode(sig, &RX, &RY, &RZ); /* Calculate the scalar part. */ sha512_init(&h); + sha512_hash(&h, pb, psz); sha512_hash(&h, sig, 32); sha512_hash(&h, K, 32); sha512_hash(&h, m, msz); - sha512_done(&h, b); - scaf_loaddbl(tt, b, 64, 2*NPIECE, PIECEWD); + sha512_done(&h, rb); + scaf_loaddbl(tt, rb, 64, 2*NPIECE, PIECEWD); scaf_reduce(t, tt, l, mu, NPIECE, PIECEWD, scratch); scaf_mul(tt, t, a, NPIECE); for (i = 0; i < NPIECE; i++) tt[i] += r[i]; @@ -468,9 +492,17 @@ void ed25519_sign(octet sig[ED25519_SIGSZ], scaf_store(sig + 32, 32, t, NPIECE, PIECEWD); } -/* --- @ed25519_verify@ --- * +void ed25519_sign(octet sig[ED25519_SIGSZ], + const void *k, size_t ksz, const octet K[ED25519_PUBSZ], + const void *m, size_t msz) + { ed25519ctx_sign(sig, k, ksz, K, -1, 0, 0, m, msz); } + +/* --- @ed25519_verify@, @ed25519ctx_verify@ --- * * * Arguments: @const octet K[ED25519_PUBSZ]@ = public key + * @int phflag@ = whether the `message' has been hashed already + * @const void *p@ = personalization string + * @size_t psz@ = length of personalization string * @const void *m@ = message to sign * @size_t msz@ = length of message * @const octet sig[ED25519_SIGSZ]@ = signature @@ -478,17 +510,23 @@ void ed25519_sign(octet sig[ED25519_SIGSZ], * Returns: Zero if OK, negative on failure. * * Use: Verify a signature. + * + * In @ed25519ctx_verify@, if @phflag@ is @-1@ then you get + * plain old Ed25519: the personalization string pointer @p@ + * will be ignored. If @phflag > 0@ then the `message' @m@ + * should be a SHA512 hash of the actual message. */ -int ed25519_verify(const octet K[ED25519_PUBSZ], - const void *m, size_t msz, - const octet sig[ED25519_SIGSZ]) +int ed25519ctx_verify(const octet K[ED25519_PUBSZ], + int phflag, const void *p, size_t psz, + const void *m, size_t msz, + const octet sig[ED25519_SIGSZ]) { sha512_ctx h; scaf_piece s[NPIECE], t[NPIECE], scratch[3*NPIECE + 1]; scaf_dblpiece tt[2*NPIECE]; f25519 AX, AY, AZ, RX, RY, RZ; - octet b[SHA512_HASHSZ]; + octet b[PREFIX_BUFSZ]; /* Unpack the public key. Negate it: we're meant to subtract the term * involving the public key point, and this is easier than negating the @@ -506,7 +544,9 @@ int ed25519_verify(const octet K[ED25519_PUBSZ], if (memcmp(b, sig + 32, 32) != 0) return (-1); /* Check the signature. */ + psz = prefix(b, phflag, p, psz); sha512_init(&h); + sha512_hash(&h, b, psz); sha512_hash(&h, sig, 32); sha512_hash(&h, K, 32); sha512_hash(&h, m, msz); @@ -521,6 +561,11 @@ int ed25519_verify(const octet K[ED25519_PUBSZ], return (0); } +int ed25519_verify(const octet K[ED25519_PUBSZ], + const void *m, size_t msz, + const octet sig[ED25519_SIGSZ]) + { return (ed25519ctx_verify(K, -1, 0, 0, m, msz, sig)); } + /*----- Test rig ----------------------------------------------------------*/ #ifdef TEST_RIG @@ -553,25 +598,43 @@ static int vrf_pubkey(dstr dv[]) return (ok); } -static int vrf_sign(dstr dv[]) +static int vrf_sign(dstr *priv, int phflag, dstr *perso, + dstr *msg, dstr *want) { + sha512_ctx h; octet K[ED25519_PUBSZ]; - dstr dsig = DSTR_INIT; + dstr d = DSTR_INIT, dsig = DSTR_INIT, *m; int ok = 1; - if (dv[2].len != ED25519_SIGSZ) die(1, "bad result length"); + if (want->len != ED25519_SIGSZ) die(1, "bad result length"); dstr_ensure(&dsig, ED25519_SIGSZ); dsig.len = ED25519_SIGSZ; - ed25519_pubkey(K, dv[0].buf, dv[0].len); - ed25519_sign((octet *)dsig.buf, dv[0].buf, dv[0].len, K, - dv[1].buf, dv[1].len); - if (memcmp(dsig.buf, dv[2].buf, ED25519_SIGSZ) != 0) { + if (phflag <= 0) + m = msg; + else { + dstr_ensure(&d, SHA512_HASHSZ); d.len = SHA512_HASHSZ; + sha512_init(&h); + sha512_hash(&h, msg->buf, msg->len); + sha512_done(&h, d.buf); + m = &d; + } + ed25519_pubkey(K, priv->buf, priv->len); + ed25519ctx_sign((octet *)dsig.buf, priv->buf, priv->len, K, + phflag, perso ? perso->buf : 0, perso ? perso->len : 0, + m->buf, m->len); + if (memcmp(dsig.buf, want->buf, ED25519_SIGSZ) != 0) { ok = 0; fprintf(stderr, "failed!"); - fprintf(stderr, "\n\tpriv = "); type_hex.dump(&dv[0], stderr); - fprintf(stderr, "\n\t msg = "); type_hex.dump(&dv[1], stderr); + fprintf(stderr, "\n\tpriv = "); type_hex.dump(priv, stderr); + if (phflag >= 0) { + fprintf(stderr, "\n\t ph = %d", phflag); + fprintf(stderr, "\n\tpers = "); type_hex.dump(perso, stderr); + } + fprintf(stderr, "\n\t msg = "); type_hex.dump(msg, stderr); + if (phflag > 0) + { fprintf(stderr, "\n\thash = "); type_hex.dump(m, stderr); } fprintf(stderr, "\n\tcalc = "); type_hex.dump(&dsig, stderr); - fprintf(stderr, "\n\twant = "); type_hex.dump(&dv[2], stderr); + fprintf(stderr, "\n\twant = "); type_hex.dump(want, stderr); fprintf(stderr, "\n"); } @@ -579,24 +642,49 @@ static int vrf_sign(dstr dv[]) return (ok); } -static int vrf_verify(dstr dv[]) +static int vrf_sign_trad(dstr *dv) + { return (vrf_sign(&dv[0], -1, 0, &dv[1], &dv[2])); } + +static int vrf_sign_ctx(dstr *dv) + { return (vrf_sign(&dv[0], *(int *)dv[1].buf, &dv[2], &dv[3], &dv[4])); } + +static int vrf_verify(dstr *pub, int phflag, dstr *perso, + dstr *msg, dstr *sig, int rc_want) { - int rc_want, rc_calc; + sha512_ctx h; + int rc_calc; + dstr d = DSTR_INIT, *m; int ok = 1; - if (dv[0].len != ED25519_PUBSZ) die(1, "bad pub length"); - if (dv[2].len != ED25519_SIGSZ) die(1, "bad sig length"); - rc_want = *(int *)dv[3].buf; - - rc_calc = ed25519_verify((const octet *)dv[0].buf, - dv[1].buf, dv[1].len, - (const octet *)dv[2].buf); + if (pub->len != ED25519_PUBSZ) die(1, "bad pub length"); + if (sig->len != ED25519_SIGSZ) die(1, "bad sig length"); + + if (phflag <= 0) + m = msg; + else { + dstr_ensure(&d, SHA512_HASHSZ); d.len = SHA512_HASHSZ; + sha512_init(&h); + sha512_hash(&h, msg->buf, msg->len); + sha512_done(&h, d.buf); + m = &d; + } + rc_calc = ed25519ctx_verify((const octet *)pub->buf, + phflag, perso ? perso->buf : 0, + perso ? perso->len : 0, + m->buf, m->len, + (const octet *)sig->buf); if (!rc_want != !rc_calc) { ok = 0; fprintf(stderr, "failed!"); - fprintf(stderr, "\n\t pub = "); type_hex.dump(&dv[0], stderr); - fprintf(stderr, "\n\t msg = "); type_hex.dump(&dv[1], stderr); - fprintf(stderr, "\n\t sig = "); type_hex.dump(&dv[2], stderr); + fprintf(stderr, "\n\t pub = "); type_hex.dump(pub, stderr); + if (phflag >= 0) { + fprintf(stderr, "\n\t ph = %d", phflag); + fprintf(stderr, "\n\tpers = "); type_hex.dump(perso, stderr); + } + fprintf(stderr, "\n\t msg = "); type_hex.dump(msg, stderr); + if (phflag > 0) + { fprintf(stderr, "\n\thash = "); type_hex.dump(m, stderr); } + fprintf(stderr, "\n\t sig = "); type_hex.dump(sig, stderr); fprintf(stderr, "\n\tcalc = %d", rc_calc); fprintf(stderr, "\n\twant = %d", rc_want); fprintf(stderr, "\n"); @@ -605,10 +693,26 @@ static int vrf_verify(dstr dv[]) return (ok); } +static int vrf_verify_trad(dstr *dv) + { return (vrf_verify(&dv[0], -1, 0, &dv[1], &dv[2], *(int *)dv[3].buf)); } + +static int vrf_verify_ctx(dstr *dv) +{ + return (vrf_verify(&dv[0], *(int *)dv[1].buf, &dv[2], + &dv[3], &dv[4], *(int *)dv[5].buf)); +} + static test_chunk tests[] = { - { "pubkey", vrf_pubkey, { &type_hex, &type_hex } }, - { "sign", vrf_sign, { &type_hex, &type_hex, &type_hex } }, - { "verify", vrf_verify, { &type_hex, &type_hex, &type_hex, &type_int } }, + { "pubkey", vrf_pubkey, + { &type_hex, &type_hex } }, + { "sign", vrf_sign_trad, + { &type_hex, &type_hex, &type_hex } }, + { "verify", vrf_verify_trad, + { &type_hex, &type_hex, &type_hex, &type_int } }, + { "sign-ctx", vrf_sign_ctx, + { &type_hex, &type_int, &type_hex, &type_hex, &type_hex } }, + { "verify-ctx", vrf_verify_ctx, + { &type_hex, &type_int, &type_hex, &type_hex, &type_hex, &type_int } }, { 0, 0, { 0 } } }; diff --git a/pub/ed25519.h b/pub/ed25519.h index 2fc74447..ac54df7f 100644 --- a/pub/ed25519.h +++ b/pub/ed25519.h @@ -44,6 +44,10 @@ * https://ed25519.cr.yp.to/eddsa-20150704.pdf. HashEdEDSA can be * implemented easily by presenting a hash of a message to the functions * here, as the message to be signed or verified. + * + * It also implements `Ed25519ctx' and `Ed25519ph' as described in RFC8032, + * though in the latter case it assumes that you've already done the hashing + * and have provided the hash as the `message' input. */ /*----- Header files ------------------------------------------------------*/ @@ -60,6 +64,8 @@ #define ED25519_PUBSZ 32u #define ED25519_SIGSZ 64u +#define ED25519_MAXPERSOSZ 255u + /*----- Key fetching ------------------------------------------------------*/ typedef struct ed25519_priv { key_bin priv, pub; } ed25519_priv; @@ -85,28 +91,46 @@ extern const key_fetchdef ed25519_pubfetch[], ed25519_privfetch[]; extern void ed25519_pubkey(octet /*K*/[ED25519_PUBSZ], const void */*k*/, size_t /*ksz*/); -/* --- @ed25519_sign@ --- * +/* --- @ed25519_sign@, @ed25519ctx_sign@ --- * * * Arguments: @octet sig[ED25519_SIGSZ]@ = where to put the signature * @const void *k@ = private key * @size_t ksz@ = length of private key * @const octet K[ED25519_PUBSZ]@ = public key + * @int phflag@ = whether the `message' has been hashed already + * @const void *p@ = personalization string + * @size_t psz@ = length of personalization string * @const void *m@ = message to sign * @size_t msz@ = length of message * * Returns: --- * * Use: Signs a message. + * + * In @ed25519ctx_sign@, if @phflag@ is @-1@ then you get plain + * old Ed25519: the personalization string pointer @p@ will be + * ignored. If @phflag > 0@ then the `message' @m@ should be a + * SHA512 hash of the actual message. */ +extern void ed25519ctx_sign(octet /*sig*/[ED25519_SIGSZ], + const void */*k*/, size_t /*ksz*/, + const octet /*K*/[ED25519_PUBSZ], + int /*phflag*/, + const void */*p*/, size_t /*psz*/, + const void */*m*/, size_t /*msz*/); + extern void ed25519_sign(octet /*sig*/[ED25519_SIGSZ], const void */*k*/, size_t /*ksz*/, const octet /*K*/[ED25519_PUBSZ], const void */*m*/, size_t /*msz*/); -/* --- @ed25519_verify@ --- * +/* --- @ed25519_verify@, @ed25519ctx_verify@ --- * * * Arguments: @const octet K[ED25519_PUBSZ]@ = public key + * @int phflag@ = whether the `message' has been hashed already + * @const void *p@ = personalization string + * @size_t psz@ = length of personalization string * @const void *m@ = message to sign * @size_t msz@ = length of message * @const octet sig[ED25519_SIGSZ]@ = signature @@ -114,8 +138,19 @@ extern void ed25519_sign(octet /*sig*/[ED25519_SIGSZ], * Returns: Zero if OK, negative on failure. * * Use: Verify a signature. + * + * In @ed25519ctx_verify@, if @phflag@ is @-1@ then you get + * plain old Ed25519: the personalization string pointer @p@ + * will be ignored. If @phflag > 0@ then the `message' @m@ + * should be a SHA512 hash of the actual message. */ +extern int ed25519ctx_verify(const octet /*K*/[ED25519_PUBSZ], + int /*phflag*/, + const void */*p*/, size_t /*psz*/, + const void */*m*/, size_t /*msz*/, + const octet /*sig*/[ED25519_SIGSZ]); + extern int ed25519_verify(const octet /*K*/[ED25519_PUBSZ], const void */*m*/, size_t /*msz*/, const octet /*sig*/[ED25519_SIGSZ]); diff --git a/pub/t/ed25519.local b/pub/t/ed25519.local index 699d4c90..451a3860 100644 --- a/pub/t/ed25519.local +++ b/pub/t/ed25519.local @@ -1,5 +1,15 @@ ### Local tests for Ed25519 +pubkey { + ## From RFC8032. + 0305334e381af78f141cb666f6199f57bc3495335a256a95bd2a55bf546663f6 + dfc9425e4f968f7f0c29f0259cf5f9aed6851c2bb4ad8bfb860cfee0ab248292; + ab9c2853ce297ddab85c993b3ae14bcad39b2c682beabc27d6d4eb20711d6560 + 0f1d1274943b91415889152e893d80e93275a1fc0b65fd71b4b0dda10ad7d772; + 833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42 + ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf; +} + verify { ## Check that noncanonical scalars are rejected. The base test is repeated ## from the main suite; let s be the scalar part of the signature, and ℓ be @@ -41,3 +51,62 @@ verify { eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000 -1; } + +sign-ctx { + ## From RFC8032. + + 0305334e381af78f141cb666f6199f57bc3495335a256a95bd2a55bf546663f6 + 0 666f6f f726936d19c800494e3fdaff20b276a8 + 55a4cc2f70a54e04288c5f4cd1e45a7bb520b36292911876cada7323198dd87a8b36950b95130022907a7fb7c4e9b2d5f6cca685a587b4b21f4b888e4e7edb0d; + 0305334e381af78f141cb666f6199f57bc3495335a256a95bd2a55bf546663f6 + 0 626172 f726936d19c800494e3fdaff20b276a8 + fc60d5872fc46b3aa69f8b5b4351d5808f92bcc044606db097abab6dbcb1aee3216c48e8b3b66431b5b186d1d28f8ee15a5ca2df6668346291c2043d4eb3e90d; + 0305334e381af78f141cb666f6199f57bc3495335a256a95bd2a55bf546663f6 + 0 666f6f 508e9e6882b979fea900f62adceaca35 + 8b70c1cc8310e1de20ac53ce28ae6e7207f33c3295e03bb5c0732a1d20dc64908922a8b052cf99b7c4fe107a5abb5b2c4085ae75890d02df26269d8945f84b0b; + ab9c2853ce297ddab85c993b3ae14bcad39b2c682beabc27d6d4eb20711d6560 + 0 666f6f f726936d19c800494e3fdaff20b276a8 + 21655b5f1aa965996b3f97b3c849eafba922a0a62992f73b3d1b73106a84ad85e9b86a7b6005ea868337ff2d20a7f5fbd4cd10b0be49a68da2b2e0dc0ad8960f; + + 833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42 + 1 "" 616263 + 98a70222f0b8121aa9d30f813d683f809e462b469c7ff87639499bb94e6dae4131f85042463c2a355a2003d062adf5aaa10b8c61e636062aaad11c2a26083406; +} + +verify-ctx { + ## From RFC8032. + + dfc9425e4f968f7f0c29f0259cf5f9aed6851c2bb4ad8bfb860cfee0ab248292 + 0 666f6f f726936d19c800494e3fdaff20b276a8 + 55a4cc2f70a54e04288c5f4cd1e45a7bb520b36292911876cada7323198dd87a8b36950b95130022907a7fb7c4e9b2d5f6cca685a587b4b21f4b888e4e7edb0d + 0; + dfc9425e4f968f7f0c29f0259cf5f9aed6851c2bb4ad8bfb860cfee0ab248292 + 0 626172 f726936d19c800494e3fdaff20b276a8 + fc60d5872fc46b3aa69f8b5b4351d5808f92bcc044606db097abab6dbcb1aee3216c48e8b3b66431b5b186d1d28f8ee15a5ca2df6668346291c2043d4eb3e90d + 0; + dfc9425e4f968f7f0c29f0259cf5f9aed6851c2bb4ad8bfb860cfee0ab248292 + 0 626172 f726936d19c800494e3fdaff20b276a8 + 55a4cc2f70a54e04288c5f4cd1e45a7bb520b36292911876cada7323198dd87a8b36950b95130022907a7fb7c4e9b2d5f6cca685a587b4b21f4b888e4e7edb0d + -1; + dfc9425e4f968f7f0c29f0259cf5f9aed6851c2bb4ad8bfb860cfee0ab248292 + 0 666f6f f726936d19c800494e3fdaff20b276a8 + fc60d5872fc46b3aa69f8b5b4351d5808f92bcc044606db097abab6dbcb1aee3216c48e8b3b66431b5b186d1d28f8ee15a5ca2df6668346291c2043d4eb3e90d + -1; + dfc9425e4f968f7f0c29f0259cf5f9aed6851c2bb4ad8bfb860cfee0ab248292 + 0 666f6f 508e9e6882b979fea900f62adceaca35 + 8b70c1cc8310e1de20ac53ce28ae6e7207f33c3295e03bb5c0732a1d20dc64908922a8b052cf99b7c4fe107a5abb5b2c4085ae75890d02df26269d8945f84b0b + 0; + 0f1d1274943b91415889152e893d80e93275a1fc0b65fd71b4b0dda10ad7d772 + 0 666f6f f726936d19c800494e3fdaff20b276a8 + 21655b5f1aa965996b3f97b3c849eafba922a0a62992f73b3d1b73106a84ad85e9b86a7b6005ea868337ff2d20a7f5fbd4cd10b0be49a68da2b2e0dc0ad8960f + 0; + + ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf + 1 "" 616263 + 98a70222f0b8121aa9d30f813d683f809e462b469c7ff87639499bb94e6dae4131f85042463c2a355a2003d062adf5aaa10b8c61e636062aaad11c2a26083406 + 0; + ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf + 1 "" 626172 + 98a70222f0b8121aa9d30f813d683f809e462b469c7ff87639499bb94e6dae4131f85042463c2a355a2003d062adf5aaa10b8c61e636062aaad11c2a26083406 + -1; +} -- 2.11.0