// Copyright (c) 2014, Google Inc.
// SPDX-License-Identifier: ISC

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <utility>
#include <vector>

#include <gtest/gtest.h>

#include <openssl/bytestring.h>
#include <openssl/crypto.h>
#include <openssl/curve25519.h>
#include <openssl/digest.h>
#include <openssl/err.h>
#include <openssl/experimental/kem_deterministic_api.h>
#include <openssl/pkcs8.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>

#include "../test/file_test.h"
#include "../test/test_util.h"
#include "../internal.h"

#include "../fipsmodule/evp/internal.h"
#include "../fipsmodule/kem/internal.h"


// kExampleRSAKeyDER is an RSA private key in ASN.1, DER format. Of course, you
// should never use this key anywhere but in an example.
static const uint8_t kExampleRSAKeyDER[] = {
    0x30, 0x82, 0x02, 0x5c, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, 0x00, 0xf8,
    0xb8, 0x6c, 0x83, 0xb4, 0xbc, 0xd9, 0xa8, 0x57, 0xc0, 0xa5, 0xb4, 0x59,
    0x76, 0x8c, 0x54, 0x1d, 0x79, 0xeb, 0x22, 0x52, 0x04, 0x7e, 0xd3, 0x37,
    0xeb, 0x41, 0xfd, 0x83, 0xf9, 0xf0, 0xa6, 0x85, 0x15, 0x34, 0x75, 0x71,
    0x5a, 0x84, 0xa8, 0x3c, 0xd2, 0xef, 0x5a, 0x4e, 0xd3, 0xde, 0x97, 0x8a,
    0xdd, 0xff, 0xbb, 0xcf, 0x0a, 0xaa, 0x86, 0x92, 0xbe, 0xb8, 0x50, 0xe4,
    0xcd, 0x6f, 0x80, 0x33, 0x30, 0x76, 0x13, 0x8f, 0xca, 0x7b, 0xdc, 0xec,
    0x5a, 0xca, 0x63, 0xc7, 0x03, 0x25, 0xef, 0xa8, 0x8a, 0x83, 0x58, 0x76,
    0x20, 0xfa, 0x16, 0x77, 0xd7, 0x79, 0x92, 0x63, 0x01, 0x48, 0x1a, 0xd8,
    0x7b, 0x67, 0xf1, 0x52, 0x55, 0x49, 0x4e, 0xd6, 0x6e, 0x4a, 0x5c, 0xd7,
    0x7a, 0x37, 0x36, 0x0c, 0xde, 0xdd, 0x8f, 0x44, 0xe8, 0xc2, 0xa7, 0x2c,
    0x2b, 0xb5, 0xaf, 0x64, 0x4b, 0x61, 0x07, 0x02, 0x03, 0x01, 0x00, 0x01,
    0x02, 0x81, 0x80, 0x74, 0x88, 0x64, 0x3f, 0x69, 0x45, 0x3a, 0x6d, 0xc7,
    0x7f, 0xb9, 0xa3, 0xc0, 0x6e, 0xec, 0xdc, 0xd4, 0x5a, 0xb5, 0x32, 0x85,
    0x5f, 0x19, 0xd4, 0xf8, 0xd4, 0x3f, 0x3c, 0xfa, 0xc2, 0xf6, 0x5f, 0xee,
    0xe6, 0xba, 0x87, 0x74, 0x2e, 0xc7, 0x0c, 0xd4, 0x42, 0xb8, 0x66, 0x85,
    0x9c, 0x7b, 0x24, 0x61, 0xaa, 0x16, 0x11, 0xf6, 0xb5, 0xb6, 0xa4, 0x0a,
    0xc9, 0x55, 0x2e, 0x81, 0xa5, 0x47, 0x61, 0xcb, 0x25, 0x8f, 0xc2, 0x15,
    0x7b, 0x0e, 0x7c, 0x36, 0x9f, 0x3a, 0xda, 0x58, 0x86, 0x1c, 0x5b, 0x83,
    0x79, 0xe6, 0x2b, 0xcc, 0xe6, 0xfa, 0x2c, 0x61, 0xf2, 0x78, 0x80, 0x1b,
    0xe2, 0xf3, 0x9d, 0x39, 0x2b, 0x65, 0x57, 0x91, 0x3d, 0x71, 0x99, 0x73,
    0xa5, 0xc2, 0x79, 0x20, 0x8c, 0x07, 0x4f, 0xe5, 0xb4, 0x60, 0x1f, 0x99,
    0xa2, 0xb1, 0x4f, 0x0c, 0xef, 0xbc, 0x59, 0x53, 0x00, 0x7d, 0xb1, 0x02,
    0x41, 0x00, 0xfc, 0x7e, 0x23, 0x65, 0x70, 0xf8, 0xce, 0xd3, 0x40, 0x41,
    0x80, 0x6a, 0x1d, 0x01, 0xd6, 0x01, 0xff, 0xb6, 0x1b, 0x3d, 0x3d, 0x59,
    0x09, 0x33, 0x79, 0xc0, 0x4f, 0xde, 0x96, 0x27, 0x4b, 0x18, 0xc6, 0xd9,
    0x78, 0xf1, 0xf4, 0x35, 0x46, 0xe9, 0x7c, 0x42, 0x7a, 0x5d, 0x9f, 0xef,
    0x54, 0xb8, 0xf7, 0x9f, 0xc4, 0x33, 0x6c, 0xf3, 0x8c, 0x32, 0x46, 0x87,
    0x67, 0x30, 0x7b, 0xa7, 0xac, 0xe3, 0x02, 0x41, 0x00, 0xfc, 0x2c, 0xdf,
    0x0c, 0x0d, 0x88, 0xf5, 0xb1, 0x92, 0xa8, 0x93, 0x47, 0x63, 0x55, 0xf5,
    0xca, 0x58, 0x43, 0xba, 0x1c, 0xe5, 0x9e, 0xb6, 0x95, 0x05, 0xcd, 0xb5,
    0x82, 0xdf, 0xeb, 0x04, 0x53, 0x9d, 0xbd, 0xc2, 0x38, 0x16, 0xb3, 0x62,
    0xdd, 0xa1, 0x46, 0xdb, 0x6d, 0x97, 0x93, 0x9f, 0x8a, 0xc3, 0x9b, 0x64,
    0x7e, 0x42, 0xe3, 0x32, 0x57, 0x19, 0x1b, 0xd5, 0x6e, 0x85, 0xfa, 0xb8,
    0x8d, 0x02, 0x41, 0x00, 0xbc, 0x3d, 0xde, 0x6d, 0xd6, 0x97, 0xe8, 0xba,
    0x9e, 0x81, 0x37, 0x17, 0xe5, 0xa0, 0x64, 0xc9, 0x00, 0xb7, 0xe7, 0xfe,
    0xf4, 0x29, 0xd9, 0x2e, 0x43, 0x6b, 0x19, 0x20, 0xbd, 0x99, 0x75, 0xe7,
    0x76, 0xf8, 0xd3, 0xae, 0xaf, 0x7e, 0xb8, 0xeb, 0x81, 0xf4, 0x9d, 0xfe,
    0x07, 0x2b, 0x0b, 0x63, 0x0b, 0x5a, 0x55, 0x90, 0x71, 0x7d, 0xf1, 0xdb,
    0xd9, 0xb1, 0x41, 0x41, 0x68, 0x2f, 0x4e, 0x39, 0x02, 0x40, 0x5a, 0x34,
    0x66, 0xd8, 0xf5, 0xe2, 0x7f, 0x18, 0xb5, 0x00, 0x6e, 0x26, 0x84, 0x27,
    0x14, 0x93, 0xfb, 0xfc, 0xc6, 0x0f, 0x5e, 0x27, 0xe6, 0xe1, 0xe9, 0xc0,
    0x8a, 0xe4, 0x34, 0xda, 0xe9, 0xa2, 0x4b, 0x73, 0xbc, 0x8c, 0xb9, 0xba,
    0x13, 0x6c, 0x7a, 0x2b, 0x51, 0x84, 0xa3, 0x4a, 0xe0, 0x30, 0x10, 0x06,
    0x7e, 0xed, 0x17, 0x5a, 0x14, 0x00, 0xc9, 0xef, 0x85, 0xea, 0x52, 0x2c,
    0xbc, 0x65, 0x02, 0x40, 0x51, 0xe3, 0xf2, 0x83, 0x19, 0x9b, 0xc4, 0x1e,
    0x2f, 0x50, 0x3d, 0xdf, 0x5a, 0xa2, 0x18, 0xca, 0x5f, 0x2e, 0x49, 0xaf,
    0x6f, 0xcc, 0xfa, 0x65, 0x77, 0x94, 0xb5, 0xa1, 0x0a, 0xa9, 0xd1, 0x8a,
    0x39, 0x37, 0xf4, 0x0b, 0xa0, 0xd7, 0x82, 0x27, 0x5e, 0xae, 0x17, 0x17,
    0xa1, 0x1e, 0x54, 0x34, 0xbf, 0x6e, 0xc4, 0x8e, 0x99, 0x5d, 0x08, 0xf1,
    0x2d, 0x86, 0x9d, 0xa5, 0x20, 0x1b, 0xe5, 0xdf,
};

static const uint8_t kExampleDSAKeyDER[] = {
    0x30, 0x82, 0x03, 0x56, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00,
    0x9e, 0x12, 0xfa, 0xb3, 0xde, 0x12, 0x21, 0x35, 0x01, 0xdd, 0x82, 0xaa,
    0x10, 0xca, 0x2d, 0x10, 0x1d, 0x2d, 0x4e, 0xbf, 0xef, 0x4d, 0x2a, 0x3f,
    0x8d, 0xaa, 0x0f, 0xe0, 0xce, 0xda, 0xd8, 0xd6, 0xaf, 0x85, 0x61, 0x6a,
    0xa2, 0xf3, 0x25, 0x2c, 0x0a, 0x2b, 0x5a, 0x6d, 0xb0, 0x9e, 0x6f, 0x14,
    0x90, 0x0e, 0x0d, 0xdb, 0x83, 0x11, 0x87, 0x6d, 0xd8, 0xf9, 0x66, 0x95,
    0x25, 0xf9, 0x9e, 0xd6, 0x59, 0x49, 0xe1, 0x84, 0xd5, 0x06, 0x47, 0x93,
    0x27, 0x11, 0x69, 0xa2, 0x28, 0x68, 0x0b, 0x95, 0xec, 0x12, 0xf5, 0x9a,
    0x8e, 0x20, 0xb2, 0x1f, 0x2b, 0x58, 0xeb, 0x2a, 0x20, 0x12, 0xd3, 0x5b,
    0xde, 0x2e, 0xe3, 0x51, 0x82, 0x2f, 0xe8, 0xf3, 0x2d, 0x0a, 0x33, 0x05,
    0x65, 0xdc, 0xce, 0x5c, 0x67, 0x2b, 0x72, 0x59, 0xc1, 0x4b, 0x24, 0x33,
    0xd0, 0xb5, 0xb2, 0xca, 0x2b, 0x2d, 0xb0, 0xab, 0x62, 0x6e, 0x8f, 0x13,
    0xf4, 0x7f, 0xe0, 0x34, 0x5d, 0x90, 0x4e, 0x72, 0x94, 0xbb, 0x03, 0x8e,
    0x9c, 0xe2, 0x1a, 0x9e, 0x58, 0x0b, 0x83, 0x35, 0x62, 0x78, 0x70, 0x6c,
    0xfe, 0x76, 0x84, 0x36, 0xc6, 0x9d, 0xe1, 0x49, 0xcc, 0xff, 0x98, 0xb4,
    0xaa, 0xb8, 0xcb, 0x4f, 0x63, 0x85, 0xc9, 0xf1, 0x02, 0xce, 0x59, 0x34,
    0x6e, 0xae, 0xef, 0x27, 0xe0, 0xad, 0x22, 0x2d, 0x53, 0xd6, 0xe8, 0x9c,
    0xc8, 0xcd, 0xe5, 0x77, 0x6d, 0xd0, 0x00, 0x57, 0xb0, 0x3f, 0x2d, 0x88,
    0xab, 0x3c, 0xed, 0xba, 0xfd, 0x7b, 0x58, 0x5f, 0x0b, 0x7f, 0x78, 0x35,
    0xe1, 0x7a, 0x37, 0x28, 0xbb, 0xf2, 0x5e, 0xa6, 0x25, 0x72, 0xf2, 0x45,
    0xdc, 0x11, 0x1f, 0x3c, 0xe3, 0x9c, 0xb6, 0xff, 0xac, 0xc3, 0x1b, 0x0a,
    0x27, 0x90, 0xe7, 0xbd, 0xe9, 0x02, 0x24, 0xea, 0x9b, 0x09, 0x31, 0x53,
    0x62, 0xaf, 0x3d, 0x2b, 0x02, 0x21, 0x00, 0xf3, 0x81, 0xdc, 0xf5, 0x3e,
    0xbf, 0x72, 0x4f, 0x8b, 0x2e, 0x5c, 0xa8, 0x2c, 0x01, 0x0f, 0xb4, 0xb5,
    0xed, 0xa9, 0x35, 0x8d, 0x0f, 0xd8, 0x8e, 0xd2, 0x78, 0x58, 0x94, 0x88,
    0xb5, 0x4f, 0xc3, 0x02, 0x82, 0x01, 0x00, 0x0c, 0x40, 0x2a, 0x72, 0x5d,
    0xcc, 0x3a, 0x62, 0xe0, 0x2b, 0xf4, 0xcf, 0x43, 0xcd, 0x17, 0xf4, 0xa4,
    0x93, 0x59, 0x12, 0x20, 0x22, 0x36, 0x69, 0xcf, 0x41, 0x93, 0xed, 0xab,
    0x42, 0x3a, 0xd0, 0x8d, 0xfb, 0x55, 0x2e, 0x30, 0x8a, 0x6a, 0x57, 0xa5,
    0xff, 0xbc, 0x7c, 0xd0, 0xfb, 0x20, 0x87, 0xf8, 0x1f, 0x8d, 0xf0, 0xcb,
    0x08, 0xab, 0x21, 0x33, 0x28, 0x7d, 0x2b, 0x69, 0x68, 0x71, 0x4a, 0x94,
    0xf6, 0x33, 0xc9, 0x40, 0x84, 0x5a, 0x48, 0xa3, 0xe1, 0x67, 0x08, 0xdd,
    0xe7, 0x61, 0xcc, 0x6a, 0x8e, 0xab, 0x2d, 0x84, 0xdb, 0x21, 0xb6, 0xea,
    0x5b, 0x07, 0x68, 0x14, 0x93, 0xcc, 0x9c, 0x31, 0xfb, 0xc3, 0x68, 0xb2,
    0x43, 0xf6, 0xdd, 0xf8, 0xc9, 0x32, 0xa8, 0xb4, 0x03, 0x8f, 0x44, 0xe7,
    0xb1, 0x5c, 0xa8, 0x76, 0x34, 0x4a, 0x14, 0x78, 0x59, 0xf2, 0xb4, 0x3b,
    0x39, 0x45, 0x86, 0x68, 0xad, 0x5e, 0x0a, 0x1a, 0x9a, 0x66, 0x95, 0x46,
    0xdd, 0x28, 0x12, 0xe3, 0xb3, 0x61, 0x7a, 0x0a, 0xef, 0x99, 0xd5, 0x8e,
    0x3b, 0xb4, 0xcc, 0x87, 0xfd, 0x94, 0x22, 0x5e, 0x01, 0xd2, 0xdc, 0xc4,
    0x69, 0xa7, 0x72, 0x68, 0x14, 0x6c, 0x51, 0x91, 0x8f, 0x18, 0xe8, 0xb4,
    0xd7, 0x0a, 0xa1, 0xf0, 0xc7, 0x62, 0x3b, 0xcc, 0x52, 0xcf, 0x37, 0x31,
    0xd3, 0x86, 0x41, 0xb2, 0xd2, 0x83, 0x0b, 0x7e, 0xec, 0xb2, 0xf0, 0x95,
    0x52, 0xff, 0x13, 0x7d, 0x04, 0x6e, 0x49, 0x4e, 0x7f, 0x33, 0xc3, 0x59,
    0x00, 0x02, 0xb1, 0x6d, 0x1b, 0x97, 0xd9, 0x36, 0xfd, 0xa2, 0x8f, 0x90,
    0xc3, 0xed, 0x3c, 0xa3, 0x53, 0x38, 0x16, 0x8a, 0xc1, 0x6f, 0x77, 0xc3,
    0xc5, 0x7a, 0xdc, 0x2e, 0x8f, 0x7c, 0x6c, 0x22, 0x56, 0xe4, 0x1a, 0x5f,
    0x65, 0x45, 0x05, 0x90, 0xdb, 0xb5, 0xbc, 0xf0, 0x6d, 0x66, 0x61, 0x02,
    0x82, 0x01, 0x00, 0x31, 0x97, 0x31, 0xa1, 0x4e, 0x38, 0x56, 0x88, 0xdb,
    0x94, 0x1d, 0xbf, 0x65, 0x5c, 0xda, 0x4b, 0xc2, 0x10, 0xde, 0x74, 0x20,
    0x03, 0xce, 0x13, 0x60, 0xf2, 0x25, 0x1d, 0x55, 0x7c, 0x5d, 0x94, 0x82,
    0x54, 0x08, 0x53, 0xdb, 0x85, 0x95, 0xbf, 0xdd, 0x5e, 0x50, 0xd5, 0x96,
    0xe0, 0x79, 0x51, 0x1b, 0xbf, 0x4d, 0x4e, 0xb9, 0x3a, 0xc5, 0xee, 0xc4,
    0x5e, 0x98, 0x75, 0x7b, 0xbe, 0xff, 0x30, 0xe6, 0xd0, 0x7b, 0xa6, 0xf1,
    0xbc, 0x29, 0xea, 0xdf, 0xec, 0xf3, 0x8b, 0xfa, 0x83, 0x11, 0x9f, 0x3f,
    0xf0, 0x5d, 0x06, 0x51, 0x32, 0xaa, 0x21, 0xfc, 0x26, 0x17, 0xe7, 0x50,
    0xc2, 0x16, 0xba, 0xfa, 0x54, 0xb7, 0x7e, 0x1d, 0x2c, 0xa6, 0xa3, 0x41,
    0x66, 0x33, 0x94, 0x83, 0xb9, 0xbf, 0xa0, 0x4f, 0xbd, 0xa6, 0xfd, 0x2c,
    0x81, 0x58, 0x35, 0x33, 0x39, 0xc0, 0x6d, 0x33, 0x40, 0x56, 0x64, 0x12,
    0x5a, 0xcd, 0x35, 0x53, 0x21, 0x78, 0x8f, 0x27, 0x24, 0x37, 0x66, 0x8a,
    0xdf, 0x5e, 0x5f, 0x63, 0xfc, 0x8b, 0x2d, 0xef, 0x57, 0xdb, 0x40, 0x25,
    0xd5, 0x17, 0x53, 0x0b, 0xe4, 0xa5, 0xae, 0x54, 0xbf, 0x46, 0x4f, 0xa6,
    0x79, 0xc3, 0x74, 0xfa, 0x1f, 0x85, 0x34, 0x64, 0x6d, 0xc5, 0x03, 0xeb,
    0x72, 0x98, 0x80, 0x7b, 0xc0, 0x8f, 0x35, 0x11, 0xa7, 0x09, 0xeb, 0x51,
    0xe0, 0xb0, 0xac, 0x92, 0x14, 0xf2, 0xad, 0x37, 0x95, 0x5a, 0xba, 0x8c,
    0xc4, 0xdb, 0xed, 0xc4, 0x4e, 0x8b, 0x8f, 0x84, 0x33, 0x64, 0xf8, 0x57,
    0x12, 0xd7, 0x08, 0x7e, 0x90, 0x66, 0xdf, 0x91, 0x50, 0x23, 0xf2, 0x73,
    0xc0, 0x6b, 0xb1, 0x15, 0xdd, 0x64, 0xd7, 0xc9, 0x75, 0x17, 0x73, 0x72,
    0xda, 0x33, 0xc4, 0x6f, 0xa5, 0x47, 0xa1, 0xcc, 0xd1, 0xc6, 0x62, 0xe5,
    0xca, 0xab, 0x5f, 0x2a, 0x8f, 0x6b, 0xcc, 0x02, 0x21, 0x00, 0xb0, 0xc7,
    0x68, 0x70, 0x27, 0x43, 0xbc, 0x51, 0x24, 0x29, 0x93, 0xa9, 0x71, 0xa5,
    0x28, 0x89, 0x79, 0x54, 0x44, 0xf7, 0xc6, 0x45, 0x22, 0x03, 0xd0, 0xce,
    0x84, 0xfe, 0x61, 0x17, 0xd4, 0x6e,
};

static const uint8_t kMsg[] = {1, 2, 3, 4};

static const uint8_t kSignature[] = {
    0xa5, 0xf0, 0x8a, 0x47, 0x5d, 0x3c, 0xb3, 0xcc, 0xa9, 0x79, 0xaf, 0x4d,
    0x8c, 0xae, 0x4c, 0x14, 0xef, 0xc2, 0x0b, 0x34, 0x36, 0xde, 0xf4, 0x3e,
    0x3d, 0xbb, 0x4a, 0x60, 0x5c, 0xc8, 0x91, 0x28, 0xda, 0xfb, 0x7e, 0x04,
    0x96, 0x7e, 0x63, 0x13, 0x90, 0xce, 0xb9, 0xb4, 0x62, 0x7a, 0xfd, 0x09,
    0x3d, 0xc7, 0x67, 0x78, 0x54, 0x04, 0xeb, 0x52, 0x62, 0x6e, 0x24, 0x67,
    0xb4, 0x40, 0xfc, 0x57, 0x62, 0xc6, 0xf1, 0x67, 0xc1, 0x97, 0x8f, 0x6a,
    0xa8, 0xae, 0x44, 0x46, 0x5e, 0xab, 0x67, 0x17, 0x53, 0x19, 0x3a, 0xda,
    0x5a, 0xc8, 0x16, 0x3e, 0x86, 0xd5, 0xc5, 0x71, 0x2f, 0xfc, 0x23, 0x48,
    0xd9, 0x0b, 0x13, 0xdd, 0x7b, 0x5a, 0x25, 0x79, 0xef, 0xa5, 0x7b, 0x04,
    0xed, 0x44, 0xf6, 0x18, 0x55, 0xe4, 0x0a, 0xe9, 0x57, 0x79, 0x5d, 0xd7,
    0x55, 0xa7, 0xab, 0x45, 0x02, 0x97, 0x60, 0x42,
};

// kExampleRSAKeyPKCS8 is kExampleRSAKeyDER encoded in a PKCS #8
// PrivateKeyInfo.
static const uint8_t kExampleRSAKeyPKCS8[] = {
    0x30, 0x82, 0x02, 0x76, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a,
    0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82,
    0x02, 0x60, 0x30, 0x82, 0x02, 0x5c, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81,
    0x00, 0xf8, 0xb8, 0x6c, 0x83, 0xb4, 0xbc, 0xd9, 0xa8, 0x57, 0xc0, 0xa5,
    0xb4, 0x59, 0x76, 0x8c, 0x54, 0x1d, 0x79, 0xeb, 0x22, 0x52, 0x04, 0x7e,
    0xd3, 0x37, 0xeb, 0x41, 0xfd, 0x83, 0xf9, 0xf0, 0xa6, 0x85, 0x15, 0x34,
    0x75, 0x71, 0x5a, 0x84, 0xa8, 0x3c, 0xd2, 0xef, 0x5a, 0x4e, 0xd3, 0xde,
    0x97, 0x8a, 0xdd, 0xff, 0xbb, 0xcf, 0x0a, 0xaa, 0x86, 0x92, 0xbe, 0xb8,
    0x50, 0xe4, 0xcd, 0x6f, 0x80, 0x33, 0x30, 0x76, 0x13, 0x8f, 0xca, 0x7b,
    0xdc, 0xec, 0x5a, 0xca, 0x63, 0xc7, 0x03, 0x25, 0xef, 0xa8, 0x8a, 0x83,
    0x58, 0x76, 0x20, 0xfa, 0x16, 0x77, 0xd7, 0x79, 0x92, 0x63, 0x01, 0x48,
    0x1a, 0xd8, 0x7b, 0x67, 0xf1, 0x52, 0x55, 0x49, 0x4e, 0xd6, 0x6e, 0x4a,
    0x5c, 0xd7, 0x7a, 0x37, 0x36, 0x0c, 0xde, 0xdd, 0x8f, 0x44, 0xe8, 0xc2,
    0xa7, 0x2c, 0x2b, 0xb5, 0xaf, 0x64, 0x4b, 0x61, 0x07, 0x02, 0x03, 0x01,
    0x00, 0x01, 0x02, 0x81, 0x80, 0x74, 0x88, 0x64, 0x3f, 0x69, 0x45, 0x3a,
    0x6d, 0xc7, 0x7f, 0xb9, 0xa3, 0xc0, 0x6e, 0xec, 0xdc, 0xd4, 0x5a, 0xb5,
    0x32, 0x85, 0x5f, 0x19, 0xd4, 0xf8, 0xd4, 0x3f, 0x3c, 0xfa, 0xc2, 0xf6,
    0x5f, 0xee, 0xe6, 0xba, 0x87, 0x74, 0x2e, 0xc7, 0x0c, 0xd4, 0x42, 0xb8,
    0x66, 0x85, 0x9c, 0x7b, 0x24, 0x61, 0xaa, 0x16, 0x11, 0xf6, 0xb5, 0xb6,
    0xa4, 0x0a, 0xc9, 0x55, 0x2e, 0x81, 0xa5, 0x47, 0x61, 0xcb, 0x25, 0x8f,
    0xc2, 0x15, 0x7b, 0x0e, 0x7c, 0x36, 0x9f, 0x3a, 0xda, 0x58, 0x86, 0x1c,
    0x5b, 0x83, 0x79, 0xe6, 0x2b, 0xcc, 0xe6, 0xfa, 0x2c, 0x61, 0xf2, 0x78,
    0x80, 0x1b, 0xe2, 0xf3, 0x9d, 0x39, 0x2b, 0x65, 0x57, 0x91, 0x3d, 0x71,
    0x99, 0x73, 0xa5, 0xc2, 0x79, 0x20, 0x8c, 0x07, 0x4f, 0xe5, 0xb4, 0x60,
    0x1f, 0x99, 0xa2, 0xb1, 0x4f, 0x0c, 0xef, 0xbc, 0x59, 0x53, 0x00, 0x7d,
    0xb1, 0x02, 0x41, 0x00, 0xfc, 0x7e, 0x23, 0x65, 0x70, 0xf8, 0xce, 0xd3,
    0x40, 0x41, 0x80, 0x6a, 0x1d, 0x01, 0xd6, 0x01, 0xff, 0xb6, 0x1b, 0x3d,
    0x3d, 0x59, 0x09, 0x33, 0x79, 0xc0, 0x4f, 0xde, 0x96, 0x27, 0x4b, 0x18,
    0xc6, 0xd9, 0x78, 0xf1, 0xf4, 0x35, 0x46, 0xe9, 0x7c, 0x42, 0x7a, 0x5d,
    0x9f, 0xef, 0x54, 0xb8, 0xf7, 0x9f, 0xc4, 0x33, 0x6c, 0xf3, 0x8c, 0x32,
    0x46, 0x87, 0x67, 0x30, 0x7b, 0xa7, 0xac, 0xe3, 0x02, 0x41, 0x00, 0xfc,
    0x2c, 0xdf, 0x0c, 0x0d, 0x88, 0xf5, 0xb1, 0x92, 0xa8, 0x93, 0x47, 0x63,
    0x55, 0xf5, 0xca, 0x58, 0x43, 0xba, 0x1c, 0xe5, 0x9e, 0xb6, 0x95, 0x05,
    0xcd, 0xb5, 0x82, 0xdf, 0xeb, 0x04, 0x53, 0x9d, 0xbd, 0xc2, 0x38, 0x16,
    0xb3, 0x62, 0xdd, 0xa1, 0x46, 0xdb, 0x6d, 0x97, 0x93, 0x9f, 0x8a, 0xc3,
    0x9b, 0x64, 0x7e, 0x42, 0xe3, 0x32, 0x57, 0x19, 0x1b, 0xd5, 0x6e, 0x85,
    0xfa, 0xb8, 0x8d, 0x02, 0x41, 0x00, 0xbc, 0x3d, 0xde, 0x6d, 0xd6, 0x97,
    0xe8, 0xba, 0x9e, 0x81, 0x37, 0x17, 0xe5, 0xa0, 0x64, 0xc9, 0x00, 0xb7,
    0xe7, 0xfe, 0xf4, 0x29, 0xd9, 0x2e, 0x43, 0x6b, 0x19, 0x20, 0xbd, 0x99,
    0x75, 0xe7, 0x76, 0xf8, 0xd3, 0xae, 0xaf, 0x7e, 0xb8, 0xeb, 0x81, 0xf4,
    0x9d, 0xfe, 0x07, 0x2b, 0x0b, 0x63, 0x0b, 0x5a, 0x55, 0x90, 0x71, 0x7d,
    0xf1, 0xdb, 0xd9, 0xb1, 0x41, 0x41, 0x68, 0x2f, 0x4e, 0x39, 0x02, 0x40,
    0x5a, 0x34, 0x66, 0xd8, 0xf5, 0xe2, 0x7f, 0x18, 0xb5, 0x00, 0x6e, 0x26,
    0x84, 0x27, 0x14, 0x93, 0xfb, 0xfc, 0xc6, 0x0f, 0x5e, 0x27, 0xe6, 0xe1,
    0xe9, 0xc0, 0x8a, 0xe4, 0x34, 0xda, 0xe9, 0xa2, 0x4b, 0x73, 0xbc, 0x8c,
    0xb9, 0xba, 0x13, 0x6c, 0x7a, 0x2b, 0x51, 0x84, 0xa3, 0x4a, 0xe0, 0x30,
    0x10, 0x06, 0x7e, 0xed, 0x17, 0x5a, 0x14, 0x00, 0xc9, 0xef, 0x85, 0xea,
    0x52, 0x2c, 0xbc, 0x65, 0x02, 0x40, 0x51, 0xe3, 0xf2, 0x83, 0x19, 0x9b,
    0xc4, 0x1e, 0x2f, 0x50, 0x3d, 0xdf, 0x5a, 0xa2, 0x18, 0xca, 0x5f, 0x2e,
    0x49, 0xaf, 0x6f, 0xcc, 0xfa, 0x65, 0x77, 0x94, 0xb5, 0xa1, 0x0a, 0xa9,
    0xd1, 0x8a, 0x39, 0x37, 0xf4, 0x0b, 0xa0, 0xd7, 0x82, 0x27, 0x5e, 0xae,
    0x17, 0x17, 0xa1, 0x1e, 0x54, 0x34, 0xbf, 0x6e, 0xc4, 0x8e, 0x99, 0x5d,
    0x08, 0xf1, 0x2d, 0x86, 0x9d, 0xa5, 0x20, 0x1b, 0xe5, 0xdf,
};

// kExampleRSAPSSKeyNoPSSParams is a sample RSAPSS private key.
// This private key has rsaPSS oid but no pss parameters.
// This key is copied from https://github.com/aws/s2n-tls/blame/c4d90e34fbd2ba64bb17a95628622ccc1d0c6807/tests/pems/rsa_pss_2048_sha256_CA_key.pem#L1
static const uint8_t kExampleRSAPSSKeyNoPSSParams[] = {
    0x30, 0x82, 0x04, 0xbb, 0x02, 0x01, 0x00, 0x30, 0x0b, 0x06, 0x09, 0x2a,
    0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0a, 0x04, 0x82, 0x04, 0xa7,
    0x30, 0x82, 0x04, 0xa3, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00,
    0xde, 0x6b, 0x53, 0x5c, 0x76, 0xb4, 0xc5, 0xc3, 0xf4, 0x22, 0x5d, 0xe4,
    0xa4, 0x6c, 0x7f, 0xe1, 0x4b, 0x0c, 0x7d, 0x28, 0xcf, 0xe5, 0x4f, 0xc3,
    0x48, 0x84, 0xb3, 0x90, 0x68, 0x23, 0xe4, 0x3a, 0xdf, 0xf5, 0x5b, 0x6e,
    0xae, 0xf9, 0x04, 0xe7, 0x3f, 0x8f, 0xbf, 0x07, 0xad, 0x90, 0x75, 0xa0,
    0x35, 0x17, 0x17, 0x6d, 0xb1, 0x7a, 0x56, 0x63, 0xf2, 0xcc, 0xc4, 0x26,
    0x23, 0xcd, 0x67, 0x82, 0x8d, 0x1c, 0x88, 0x51, 0x85, 0xfe, 0x58, 0x08,
    0x2d, 0xc4, 0x4e, 0x45, 0x22, 0x1e, 0xd8, 0x53, 0x79, 0xc7, 0x4c, 0xbe,
    0x24, 0x14, 0xed, 0x82, 0xf2, 0x96, 0xf9, 0x59, 0x71, 0x51, 0x94, 0x15,
    0xbd, 0xe2, 0x67, 0x26, 0x27, 0xda, 0x8c, 0x33, 0x2a, 0xd6, 0x19, 0xfa,
    0xf3, 0x83, 0xb8, 0x8f, 0x6e, 0x1d, 0xda, 0xd8, 0xa1, 0xcc, 0x33, 0xbb,
    0x90, 0x6b, 0xc8, 0xac, 0x12, 0x27, 0x4e, 0xd5, 0x11, 0x32, 0x6f, 0x2b,
    0xf3, 0x52, 0x07, 0x0e, 0xf5, 0x2c, 0x97, 0xb8, 0x7b, 0x17, 0xc6, 0x18,
    0x94, 0xad, 0x2e, 0x52, 0x14, 0x6c, 0x09, 0x0d, 0xfc, 0x05, 0xd2, 0x9d,
    0xf7, 0xec, 0xa5, 0x44, 0x68, 0xb3, 0xdc, 0xf5, 0xdf, 0xd8, 0x93, 0xef,
    0xbd, 0x07, 0xec, 0x60, 0x87, 0x54, 0xec, 0x14, 0x16, 0xa4, 0x79, 0xb7,
    0xab, 0xd0, 0x7e, 0x63, 0x72, 0x99, 0xe8, 0x33, 0x12, 0xe1, 0x1c, 0xdd,
    0xbe, 0xff, 0xc9, 0x3f, 0x2b, 0xb5, 0xbf, 0x06, 0x4d, 0x8e, 0xc2, 0xb1,
    0xd7, 0xfb, 0x2f, 0x2d, 0x80, 0x6a, 0x9c, 0xb0, 0x55, 0xdf, 0x85, 0x2f,
    0x08, 0x89, 0x62, 0x1e, 0xca, 0xb1, 0xbd, 0x9a, 0x1b, 0xd2, 0xb6, 0x74,
    0xcd, 0x8e, 0x1e, 0xf2, 0xad, 0x58, 0xd6, 0xa5, 0x69, 0x96, 0xed, 0xf5,
    0x19, 0xf0, 0x7c, 0xf1, 0xb6, 0x08, 0x23, 0xae, 0x61, 0x7c, 0x9d, 0x43,
    0x46, 0x90, 0x4f, 0xaf, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x82, 0x01,
    0x00, 0x23, 0x14, 0xe8, 0x9c, 0x1f, 0xf9, 0x19, 0x6c, 0x73, 0xf8, 0x6b,
    0xb8, 0xe1, 0x9a, 0x5f, 0x7d, 0x48, 0x9a, 0x1a, 0xaf, 0xb2, 0x42, 0xe8,
    0x16, 0xd4, 0x3c, 0x62, 0x1a, 0x37, 0xe2, 0xd9, 0x5f, 0xd3, 0xed, 0x5e,
    0x53, 0x91, 0xf3, 0xa3, 0x2b, 0x5a, 0x62, 0x30, 0xee, 0x64, 0x18, 0xf2,
    0x04, 0xa7, 0xfb, 0x11, 0x6d, 0xf2, 0xdd, 0x69, 0xfc, 0xef, 0xd2, 0x0e,
    0x6a, 0x39, 0xa1, 0x6f, 0x5f, 0x2f, 0x24, 0xbd, 0xf7, 0xa5, 0xdb, 0xdd,
    0x44, 0xc4, 0xfb, 0x3e, 0xa1, 0x36, 0xe5, 0x88, 0x97, 0x7a, 0x10, 0xce,
    0x70, 0xfb, 0x3d, 0xf5, 0xcc, 0x7e, 0xb9, 0x03, 0x71, 0x71, 0x27, 0x3d,
    0xe5, 0x44, 0x03, 0x0e, 0xe3, 0xfc, 0xcb, 0x42, 0xeb, 0xdb, 0x28, 0xd4,
    0x06, 0x3a, 0x1c, 0x9f, 0xa2, 0xb7, 0xea, 0xab, 0x97, 0x19, 0xc6, 0x1c,
    0xae, 0xcb, 0xf3, 0xc4, 0x3e, 0x27, 0xca, 0xdd, 0x6b, 0x00, 0xb6, 0xad,
    0x07, 0xf7, 0x04, 0x5a, 0xb4, 0x06, 0x3d, 0x7d, 0x08, 0x99, 0x68, 0xdd,
    0x62, 0x2d, 0x93, 0x76, 0x21, 0xfe, 0x31, 0xa1, 0xeb, 0xcc, 0x20, 0x11,
    0xdb, 0x5b, 0x03, 0x3c, 0xf2, 0x60, 0x29, 0x2c, 0x1f, 0xda, 0x3c, 0x31,
    0x07, 0xf1, 0x0f, 0xce, 0x08, 0xa0, 0x62, 0x6d, 0x5a, 0x33, 0xf2, 0xd4,
    0x16, 0x25, 0x0e, 0xb6, 0xf3, 0x23, 0xdd, 0xf4, 0xff, 0xf5, 0xab, 0x13,
    0x35, 0x62, 0xd7, 0x06, 0xfc, 0xaf, 0xa9, 0x74, 0xc1, 0x9a, 0x67, 0xb1,
    0xf0, 0xfa, 0xeb, 0xed, 0x63, 0x2a, 0x82, 0x17, 0xd1, 0xeb, 0x88, 0xa6,
    0x09, 0x97, 0xf9, 0x4b, 0x00, 0x49, 0x70, 0x5f, 0x35, 0x25, 0x48, 0xae,
    0xf2, 0xa0, 0xde, 0xb6, 0xb9, 0x62, 0x6d, 0x64, 0x77, 0x05, 0x64, 0xcb,
    0x56, 0xdc, 0xd2, 0xbf, 0x16, 0xe7, 0x10, 0x80, 0x52, 0x4f, 0x04, 0x85,
    0x31, 0x22, 0x1c, 0x1a, 0x71, 0x02, 0x81, 0x81, 0x00, 0xf3, 0x16, 0xe7,
    0xf4, 0x9c, 0x1a, 0xfb, 0x23, 0xe3, 0x63, 0x5a, 0x2e, 0x51, 0x7b, 0xb0,
    0x68, 0xe2, 0xa8, 0x9d, 0x1a, 0x6e, 0x43, 0x9e, 0x22, 0x47, 0x01, 0x48,
    0x91, 0xd2, 0xbf, 0xde, 0x30, 0x91, 0xbb, 0x23, 0xa2, 0x25, 0xd3, 0x96,
    0x7d, 0xc6, 0x22, 0x2f, 0xf6, 0x18, 0x99, 0x63, 0x5a, 0xf5, 0x69, 0xc0,
    0x44, 0x43, 0x4b, 0x21, 0xd4, 0xd2, 0x14, 0x22, 0xb1, 0xf9, 0x8d, 0xde,
    0xa9, 0x20, 0x68, 0x7c, 0x38, 0x28, 0xab, 0x7a, 0x77, 0x08, 0x19, 0x80,
    0x52, 0xff, 0xfa, 0xe5, 0xd3, 0xba, 0x33, 0x92, 0x4c, 0x4d, 0x6a, 0x4f,
    0xf3, 0x08, 0xf6, 0x75, 0x20, 0xc1, 0xca, 0xe9, 0x1d, 0xb4, 0xd3, 0x56,
    0xd6, 0x51, 0x32, 0x75, 0x6c, 0x07, 0x4b, 0x4c, 0x15, 0x8f, 0x63, 0x79,
    0x27, 0xcb, 0x79, 0x9c, 0x03, 0xd3, 0xf5, 0x90, 0xb5, 0xee, 0xce, 0x92,
    0xac, 0x07, 0x12, 0x89, 0xa9, 0x02, 0x81, 0x81, 0x00, 0xea, 0x3b, 0x62,
    0x00, 0xae, 0xa7, 0x5d, 0x56, 0x67, 0x76, 0x31, 0xf8, 0xda, 0x59, 0x52,
    0x82, 0x53, 0x7f, 0x49, 0x7c, 0x4a, 0x69, 0x4c, 0xd8, 0x4a, 0x35, 0x34,
    0x26, 0x86, 0x0a, 0xdf, 0xf3, 0x97, 0xae, 0xb1, 0x6d, 0x20, 0x85, 0xbd,
    0x20, 0x49, 0x2c, 0xa3, 0x11, 0xef, 0x76, 0x38, 0xe3, 0x7e, 0xf7, 0x36,
    0x8a, 0xa2, 0x79, 0xb8, 0xbc, 0xd1, 0xad, 0xf1, 0xbc, 0xc4, 0x5a, 0xac,
    0xf8, 0x43, 0xd7, 0x20, 0x28, 0xd9, 0xa0, 0xfa, 0xce, 0x8a, 0xfd, 0xee,
    0x53, 0x22, 0x13, 0xa5, 0x3a, 0x5f, 0xd4, 0x11, 0xe4, 0xf3, 0xf6, 0x78,
    0x1e, 0xa6, 0xab, 0x3e, 0xf9, 0xe9, 0xae, 0x52, 0xf9, 0x8d, 0xf5, 0x30,
    0x6e, 0xea, 0x7b, 0x39, 0x30, 0x0a, 0x4f, 0x0c, 0x65, 0x8e, 0x79, 0x14,
    0x13, 0xa9, 0x36, 0xe9, 0x68, 0x5e, 0x75, 0x8d, 0x47, 0x77, 0x4a, 0x5a,
    0xfc, 0xe7, 0x0c, 0x55, 0x97, 0x02, 0x81, 0x81, 0x00, 0xe1, 0xc8, 0x49,
    0xc3, 0x79, 0xe6, 0xd9, 0x92, 0x98, 0xd6, 0x23, 0xe1, 0xd7, 0x8f, 0x01,
    0xe8, 0x39, 0x76, 0x11, 0x0d, 0x86, 0x92, 0xc9, 0x62, 0xde, 0xfe, 0x83,
    0x2f, 0xe6, 0x46, 0x8d, 0x92, 0x21, 0x19, 0x67, 0x5c, 0x68, 0xb3, 0xe1,
    0x18, 0x8b, 0x1a, 0x1f, 0xdf, 0xfd, 0x33, 0x23, 0x04, 0x4d, 0xe3, 0x5e,
    0x50, 0x49, 0x0c, 0x94, 0xac, 0xbe, 0x3f, 0x33, 0x86, 0x88, 0xda, 0xcb,
    0x8f, 0xdc, 0xe9, 0x0f, 0x4f, 0x7d, 0xfe, 0xdf, 0xad, 0x85, 0x59, 0x62,
    0x46, 0x35, 0x3a, 0x0d, 0x93, 0x9d, 0x63, 0xdf, 0x23, 0x7d, 0xd8, 0x1b,
    0xd0, 0x09, 0x68, 0x18, 0x9c, 0x47, 0x43, 0x37, 0x48, 0x7f, 0x36, 0xb8,
    0x76, 0x31, 0x4e, 0xa3, 0x9f, 0xa6, 0x1a, 0xba, 0xdd, 0x5f, 0xa4, 0x2d,
    0xd8, 0xd7, 0x75, 0xe9, 0x81, 0xe8, 0xb2, 0x32, 0x29, 0xb9, 0x58, 0x27,
    0x05, 0x1f, 0x40, 0x89, 0x99, 0x02, 0x81, 0x80, 0x03, 0x11, 0xf2, 0x2f,
    0xe6, 0x1a, 0x25, 0x7c, 0x0b, 0x71, 0x1e, 0x28, 0x8f, 0xdc, 0x19, 0xdb,
    0xc1, 0x72, 0x6a, 0xa9, 0x29, 0x64, 0x85, 0xf0, 0x53, 0xd0, 0xac, 0xb5,
    0x50, 0x8e, 0x75, 0xef, 0x00, 0x6e, 0xf6, 0xbe, 0x62, 0x6d, 0xbe, 0x53,
    0xdd, 0x01, 0xab, 0xc5, 0x81, 0x69, 0x00, 0x47, 0xe3, 0x13, 0x24, 0x70,
    0xde, 0xbe, 0x4f, 0xb0, 0x91, 0xe3, 0x00, 0xc7, 0x23, 0x9f, 0xb8, 0xa2,
    0xac, 0x68, 0xf6, 0x6f, 0xf2, 0xa2, 0x4c, 0x87, 0x46, 0x85, 0x1b, 0x89,
    0x95, 0x69, 0xc2, 0x81, 0xa8, 0x5d, 0xe4, 0x3a, 0x27, 0x04, 0x75, 0x00,
    0x99, 0xd8, 0xa6, 0xc3, 0xa9, 0xcf, 0x72, 0x20, 0xf9, 0x3e, 0x5c, 0x7b,
    0x27, 0xb1, 0xa3, 0xc7, 0x40, 0x6b, 0x56, 0xd3, 0x41, 0xf1, 0xce, 0x54,
    0x8f, 0xa4, 0x3b, 0x9c, 0xf5, 0x97, 0xfe, 0xd9, 0x0f, 0xf4, 0x36, 0x8b,
    0x18, 0x10, 0x2e, 0x53, 0x02, 0x81, 0x80, 0x72, 0xc7, 0x72, 0x18, 0x07,
    0xe4, 0x0b, 0x07, 0x1e, 0xa6, 0x4a, 0x7b, 0x10, 0x6f, 0xdf, 0xfc, 0xf5,
    0xd6, 0x1d, 0x6d, 0x7e, 0xb4, 0xab, 0x14, 0x5d, 0x9c, 0x2f, 0x39, 0x14,
    0x5c, 0xd1, 0x6a, 0x4f, 0xbe, 0x06, 0x4c, 0xa5, 0xcb, 0x48, 0x3a, 0xee,
    0x46, 0xb4, 0xd7, 0x4a, 0xea, 0xef, 0x40, 0x94, 0x1b, 0xe1, 0x7f, 0x19,
    0xa0, 0x3a, 0xd8, 0xb4, 0x75, 0x9f, 0x2c, 0x46, 0x85, 0x26, 0x53, 0x97,
    0x1e, 0x6f, 0xb4, 0xb0, 0x55, 0x1f, 0x76, 0x14, 0xd2, 0xc5, 0x0b, 0xe2,
    0x2b, 0x48, 0x50, 0x73, 0x1b, 0x43, 0x88, 0x5e, 0xee, 0x5e, 0xdc, 0x2a,
    0x5d, 0x40, 0x5b, 0x94, 0xa1, 0xd7, 0xab, 0xec, 0x24, 0x76, 0xf8, 0x8a,
    0xee, 0x80, 0xcd, 0x22, 0x20, 0x93, 0x2a, 0x73, 0x08, 0x85, 0x47, 0x13,
    0xe0, 0x6c, 0x08, 0x5b, 0xa3, 0xb8, 0x04, 0x5e, 0x12, 0xd1, 0xef, 0x49,
    0xda, 0xf6, 0xbd};

// kExampleRSAPSSKeyPKCS8 contains a DER-encoded RSASSA-PSS-params:
//    Hash Algorithm: sha256
//    Mask Algorithm: mgf1 with sha256
static const uint8_t kExampleRSAPSSKeyPKCS8[] = {
    0x30, 0x82, 0x04, 0xea, 0x02, 0x01, 0x00, 0x30, 0x38, 0x06, 0x09, 0x2a,
    0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0a, 0x30, 0x2b, 0xa0, 0x0d,
    0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02,
    0x01, 0xa1, 0x1a, 0x30, 0x18, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
    0x0d, 0x01, 0x01, 0x08, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
    0x65, 0x03, 0x04, 0x02, 0x01, 0x04, 0x82, 0x04, 0xa9, 0x30, 0x82, 0x04,
    0xa5, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00, 0xd6, 0xe6, 0x38,
    0xa9, 0x70, 0x5c, 0x90, 0xf5, 0xd6, 0xaf, 0x78, 0xbb, 0x00, 0x05, 0xf3,
    0x7a, 0x6a, 0x3c, 0x0c, 0x12, 0x56, 0x32, 0xb6, 0xf5, 0x91, 0xbd, 0xad,
    0x3b, 0x22, 0x06, 0xbb, 0x3e, 0xc6, 0x01, 0x89, 0x14, 0xed, 0xcc, 0x0e,
    0xa5, 0xb1, 0x80, 0x69, 0x6b, 0x23, 0x83, 0xf2, 0x1f, 0x1c, 0x1c, 0x62,
    0x9d, 0x30, 0x61, 0x94, 0x45, 0x25, 0xf0, 0xf6, 0xe3, 0xb0, 0x84, 0xdc,
    0x5c, 0x80, 0x3d, 0xcb, 0xd6, 0x4c, 0xd7, 0x3f, 0x65, 0x1f, 0x72, 0x15,
    0xf9, 0x36, 0xa9, 0x70, 0x80, 0x65, 0xce, 0x92, 0xfb, 0x79, 0xa1, 0x39,
    0x67, 0xf9, 0xb4, 0x7f, 0x5b, 0xac, 0x74, 0xd2, 0x1d, 0x11, 0xb3, 0x58,
    0x37, 0x58, 0xae, 0xfc, 0x84, 0xd0, 0xe7, 0xe8, 0x96, 0xab, 0xcc, 0x9c,
    0x60, 0x01, 0x25, 0x79, 0x18, 0x9f, 0xa8, 0xbb, 0x37, 0xa8, 0x30, 0x56,
    0x01, 0x40, 0xe4, 0x28, 0x4d, 0x75, 0x0a, 0x21, 0x7c, 0xf4, 0xe1, 0x5e,
    0xd4, 0x44, 0x87, 0x55, 0xf8, 0xa7, 0xc8, 0xc3, 0x36, 0x30, 0x18, 0xc8,
    0xbe, 0x6e, 0x1a, 0x2e, 0x08, 0x36, 0x44, 0xa2, 0x68, 0xf8, 0x7e, 0xb7,
    0xe2, 0xd3, 0x7b, 0xcf, 0x5e, 0xd1, 0x8b, 0x17, 0x7b, 0x78, 0x75, 0x75,
    0x99, 0x35, 0x1e, 0x4a, 0xbc, 0x48, 0x3d, 0xb7, 0x25, 0x1b, 0xcc, 0xf1,
    0x1c, 0xbf, 0x8b, 0x9a, 0xd9, 0xba, 0xca, 0x02, 0x7f, 0x69, 0x8e, 0xbe,
    0xed, 0xd7, 0x4d, 0x8e, 0xfa, 0x8c, 0x76, 0x43, 0xe3, 0x2b, 0xa8, 0xbe,
    0xb1, 0xf2, 0x24, 0xd3, 0xf0, 0x34, 0x30, 0xd4, 0x8e, 0x85, 0x3c, 0x68,
    0xea, 0xf7, 0x0a, 0x44, 0xcf, 0x66, 0xb0, 0xa9, 0x28, 0x54, 0x19, 0x00,
    0xb5, 0x7f, 0xce, 0x65, 0xa3, 0xae, 0xce, 0xd7, 0x20, 0x88, 0x96, 0xc1,
    0xe9, 0x62, 0x02, 0xab, 0x15, 0x3d, 0x70, 0x34, 0xb9, 0xf9, 0xa5, 0x92,
    0xdf, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x82, 0x01, 0x00, 0x77, 0xd2,
    0xba, 0x79, 0x4f, 0x9b, 0x6d, 0x80, 0x86, 0x0a, 0x25, 0x29, 0x2f, 0xa4,
    0x21, 0xd4, 0x79, 0xf3, 0xad, 0x4f, 0x74, 0x1c, 0xa7, 0x03, 0x5a, 0x16,
    0x06, 0xc7, 0x57, 0xfb, 0xa4, 0xe0, 0x25, 0x8b, 0xa9, 0xa1, 0xaf, 0xcd,
    0xfd, 0xc4, 0xc9, 0xaa, 0x2e, 0x1d, 0x7d, 0x1a, 0x0f, 0x20, 0xe5, 0x8d,
    0xb6, 0x36, 0xab, 0x49, 0x5d, 0x61, 0x08, 0xfc, 0xc8, 0xcc, 0xc0, 0x19,
    0xf4, 0xbc, 0xe7, 0x0c, 0x8d, 0xe1, 0x99, 0xca, 0xd3, 0x20, 0x51, 0x5e,
    0x4d, 0x7e, 0x3d, 0xca, 0x50, 0x5e, 0x67, 0x65, 0xbd, 0x72, 0xd6, 0xa8,
    0xdc, 0xd7, 0x6a, 0xd6, 0x07, 0xc5, 0x57, 0xed, 0x73, 0x52, 0x9e, 0x11,
    0xff, 0xf8, 0x2c, 0x4c, 0xb5, 0xa4, 0x60, 0xcf, 0x4e, 0x52, 0xe4, 0xcc,
    0x1b, 0xcd, 0x34, 0x16, 0x6e, 0xe5, 0x19, 0xf0, 0xfd, 0x22, 0xd5, 0x76,
    0xce, 0x1d, 0xb8, 0xce, 0xfe, 0xe0, 0xdb, 0x74, 0x19, 0xa9, 0x27, 0xb6,
    0x30, 0x9e, 0x63, 0xa9, 0xf8, 0x2e, 0x06, 0xae, 0xc5, 0x85, 0x32, 0x60,
    0xa0, 0xb0, 0x7c, 0x35, 0x65, 0xe5, 0xd5, 0xdc, 0xfc, 0x97, 0xd1, 0x57,
    0xb8, 0x84, 0xd4, 0xbf, 0x1d, 0x0b, 0x6c, 0xe9, 0x2c, 0x57, 0xeb, 0x5c,
    0x51, 0x12, 0x76, 0x0e, 0x57, 0x9d, 0x6c, 0x44, 0xe8, 0x5a, 0xfe, 0x1b,
    0x66, 0xb5, 0x38, 0x72, 0x31, 0x15, 0x91, 0xe6, 0xc5, 0xb6, 0xad, 0xf0,
    0x89, 0x31, 0xdb, 0x88, 0x2c, 0x52, 0xf8, 0x3f, 0x72, 0x2c, 0x4f, 0x9a,
    0x93, 0x55, 0xd4, 0xf4, 0xe2, 0x34, 0x73, 0xf0, 0x07, 0x34, 0xe6, 0xbf,
    0x70, 0x94, 0x73, 0x5f, 0xe1, 0x3a, 0xe3, 0x37, 0x3f, 0xaf, 0x38, 0x24,
    0xbd, 0x12, 0x2f, 0xba, 0xcc, 0x89, 0x15, 0xe0, 0xcd, 0x43, 0x27, 0x8c,
    0xbd, 0x3e, 0x52, 0xac, 0x08, 0x86, 0x32, 0x81, 0x0d, 0xe4, 0x9d, 0x83,
    0xfa, 0x11, 0x02, 0x81, 0x81, 0x00, 0xf9, 0xae, 0x0e, 0xed, 0xb1, 0x57,
    0xf1, 0x90, 0xa5, 0xeb, 0x5d, 0x08, 0x7d, 0x1c, 0xe2, 0x4c, 0xab, 0x15,
    0xa6, 0x7d, 0xb2, 0xa1, 0x01, 0x80, 0x97, 0xb0, 0x3f, 0x1d, 0x02, 0x19,
    0xa0, 0xb0, 0x61, 0xd7, 0xff, 0x23, 0x88, 0xa3, 0x32, 0xe7, 0xbf, 0xfe,
    0xf7, 0x7d, 0xe4, 0x5e, 0xed, 0xa2, 0xe2, 0x52, 0xb6, 0xa6, 0x13, 0x83,
    0x12, 0x4e, 0xf5, 0x33, 0xf6, 0x33, 0xf4, 0x0c, 0x90, 0x97, 0x7a, 0x0a,
    0xac, 0x12, 0xa5, 0x80, 0x16, 0x5c, 0x96, 0x60, 0xed, 0x78, 0xd2, 0x77,
    0x8f, 0xc8, 0xcd, 0xe5, 0x0d, 0x55, 0x2b, 0x13, 0xbf, 0xe0, 0x48, 0xbe,
    0xe0, 0xd1, 0x01, 0x3a, 0x4d, 0xe3, 0x9d, 0x9c, 0xe5, 0xe2, 0xd9, 0xc9,
    0xd1, 0x39, 0x90, 0xed, 0xdc, 0xcd, 0x10, 0x16, 0xf4, 0x92, 0x41, 0x12,
    0xd2, 0x4a, 0x78, 0x81, 0x47, 0xe5, 0x4b, 0x46, 0x55, 0x97, 0x7b, 0xab,
    0xc2, 0xbb, 0x02, 0x81, 0x81, 0x00, 0xdc, 0x56, 0xc8, 0x4e, 0x1a, 0x0d,
    0xd4, 0xbf, 0x52, 0xb8, 0xc0, 0xae, 0xd3, 0x79, 0x41, 0x20, 0xb9, 0x87,
    0x19, 0x38, 0xc8, 0x19, 0x2a, 0xfe, 0x6f, 0xcd, 0xe3, 0x0f, 0x56, 0x0d,
    0x97, 0x57, 0x1d, 0xd6, 0xbe, 0xf0, 0x19, 0xc0, 0xf2, 0x5e, 0xd8, 0x15,
    0xab, 0xf2, 0x36, 0x62, 0xfd, 0x59, 0x09, 0xc3, 0x75, 0x2e, 0xcc, 0xf2,
    0xb3, 0x52, 0x91, 0x31, 0xc9, 0xb9, 0x1a, 0xe0, 0x15, 0x61, 0x1f, 0x1e,
    0x22, 0x39, 0x4d, 0x9d, 0x62, 0xae, 0x6f, 0x3c, 0x65, 0xe6, 0x4b, 0x30,
    0x4b, 0x40, 0xae, 0x97, 0x68, 0x7f, 0x1c, 0x31, 0x8e, 0xa8, 0x00, 0x68,
    0x59, 0xef, 0x5d, 0xc2, 0x7b, 0x40, 0x8c, 0xf0, 0x9a, 0x28, 0xb6, 0xbd,
    0x80, 0x72, 0xe3, 0xe6, 0x3c, 0x39, 0xbb, 0x9c, 0x3f, 0x2b, 0xad, 0x23,
    0xd0, 0x28, 0x72, 0x88, 0x7f, 0x2e, 0x21, 0x9c, 0x69, 0x37, 0xd9, 0x73,
    0x88, 0x2d, 0x02, 0x81, 0x81, 0x00, 0xc7, 0xcb, 0x84, 0x00, 0xaa, 0xa8,
    0x20, 0x12, 0xca, 0xe2, 0xb3, 0x98, 0xa6, 0x5d, 0x65, 0xad, 0x4a, 0x3e,
    0x51, 0xf3, 0x45, 0xec, 0xd7, 0x01, 0xea, 0xe0, 0x4b, 0x30, 0xd0, 0x4c,
    0x67, 0xac, 0x9d, 0x2f, 0x35, 0xe8, 0x5e, 0x5f, 0x91, 0xcd, 0xa7, 0x72,
    0xc4, 0xe3, 0x45, 0xca, 0xbc, 0xc8, 0x59, 0xe9, 0x2c, 0x65, 0x6b, 0x39,
    0xb8, 0x7d, 0xdc, 0x73, 0x4f, 0x31, 0xb5, 0xba, 0x14, 0x3e, 0x52, 0x97,
    0x95, 0xa8, 0x7a, 0x2d, 0x2c, 0x37, 0xbc, 0xd2, 0x25, 0x55, 0x48, 0xbe,
    0x0a, 0x1d, 0xfa, 0xbc, 0xae, 0xd5, 0x97, 0x59, 0xff, 0x71, 0xdf, 0x64,
    0x77, 0x0c, 0x68, 0xba, 0x1a, 0x37, 0xe9, 0x18, 0xf3, 0x50, 0x7b, 0x4c,
    0xa7, 0x13, 0x34, 0xa9, 0x52, 0xc5, 0xf9, 0x79, 0x15, 0x0e, 0xaf, 0xe9,
    0xfa, 0xc3, 0x42, 0xf8, 0xd8, 0xea, 0x60, 0x39, 0x11, 0x26, 0xdd, 0xfc,
    0xcd, 0x1f, 0x02, 0x81, 0x81, 0x00, 0xbf, 0x70, 0x53, 0x36, 0xb0, 0xa2,
    0x65, 0xbf, 0x19, 0x73, 0x56, 0x4e, 0x4f, 0x84, 0xe1, 0x96, 0x3a, 0x3b,
    0xec, 0x29, 0x0e, 0x89, 0xf7, 0x75, 0xfb, 0xd4, 0x29, 0xbc, 0xd0, 0x6a,
    0x9c, 0x9c, 0x5f, 0x5b, 0x8e, 0xa7, 0xf3, 0xe8, 0x55, 0x6d, 0x1c, 0x57,
    0xaf, 0xfe, 0x91, 0x4c, 0x6e, 0x8c, 0xa6, 0xd4, 0x01, 0x03, 0x79, 0xa4,
    0x41, 0x33, 0xb2, 0xdd, 0x4c, 0x44, 0x1c, 0xda, 0xa7, 0x18, 0xac, 0x3d,
    0xb5, 0x44, 0x8e, 0x6f, 0xf9, 0x26, 0x4f, 0x95, 0x6d, 0x7f, 0xaa, 0xc2,
    0x3a, 0x0f, 0xe7, 0xe1, 0xbb, 0x33, 0xfd, 0x5d, 0xfd, 0x71, 0x70, 0x71,
    0x39, 0xfa, 0xa4, 0x3e, 0xee, 0x71, 0x86, 0x43, 0x21, 0xdd, 0xcf, 0xf0,
    0x54, 0x22, 0xfe, 0x69, 0xb2, 0xd8, 0x02, 0x6e, 0x5d, 0xe0, 0x67, 0xdd,
    0x5e, 0xe5, 0x55, 0xa5, 0xcc, 0xc2, 0x5b, 0x07, 0x97, 0xcf, 0xa3, 0x8a,
    0x22, 0xbd, 0x02, 0x81, 0x81, 0x00, 0xee, 0x18, 0x67, 0x30, 0x7d, 0x7d,
    0xd1, 0x5b, 0xef, 0x28, 0xfe, 0x1e, 0xf9, 0x27, 0x07, 0x7b, 0x3b, 0xcf,
    0xb1, 0xa2, 0x62, 0xe6, 0xd2, 0x04, 0x19, 0xb3, 0x0d, 0xfe, 0xb6, 0xc4,
    0x5d, 0x56, 0x71, 0xb7, 0x85, 0xea, 0x24, 0x69, 0x73, 0x36, 0x10, 0xf2,
    0x45, 0x18, 0x1d, 0xa0, 0xc9, 0x5b, 0x59, 0xbb, 0xd5, 0xe0, 0x7c, 0x52,
    0x73, 0x78, 0x46, 0x61, 0xf2, 0x0d, 0x6a, 0xe0, 0xf0, 0x62, 0xac, 0xc0,
    0x63, 0xcc, 0xbe, 0x61, 0xa2, 0x6a, 0x06, 0xeb, 0x30, 0x41, 0x93, 0xa6,
    0x5d, 0xae, 0xf8, 0x8d, 0xf8, 0x0b, 0xca, 0x7f, 0x8f, 0x76, 0xef, 0x4a,
    0x3a, 0x37, 0x80, 0x9e, 0x17, 0x27, 0x6b, 0xb2, 0x5c, 0x37, 0x0f, 0x42,
    0x20, 0x5f, 0xaf, 0xee, 0x4c, 0x55, 0xeb, 0x6d, 0x44, 0xe0, 0x8a, 0x94,
    0xe5, 0x7a, 0xa5, 0x8c, 0x31, 0xe5, 0xae, 0xe3, 0x27, 0xa7, 0x8e, 0xa8,
    0x94, 0xc2};

// badRSAPSSKeyPKCS8_SaltLengthTooLarge is encoded in a PKCS #8 PrivateKeyInfo.
// badRSAPSSKeyPKCS8_SaltLengthTooLarge contains a DER-encoded RSASSA-PSS-params:
//    Hash Algorithm: sha256
//    Mask Algorithm: mgf1 with sha256
//    Salt Length: 511
static const uint8_t badRSAPSSKeyPKCS8_SaltLengthTooLarge[] = {
    0x30, 0x82, 0x04, 0xed, 0x02, 0x01, 0x00, 0x30, 0x3e, 0x06, 0x09, 0x2a,
    0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0a, 0x30, 0x31, 0xa0, 0x0d,
    0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02,
    0x01, 0xa1, 0x1a, 0x30, 0x18, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
    0x0d, 0x01, 0x01, 0x08, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
    0x65, 0x03, 0x04, 0x02, 0x01, 0xa2, 0x04, 0x02, 0x02, 0x01, 0xff, 0x04,
    0x82, 0x04, 0xa6, 0x30, 0x82, 0x04, 0xa2, 0x02, 0x01, 0x00, 0x02, 0x82,
    0x01, 0x01, 0x00, 0xc4, 0xd8, 0xc8, 0x45, 0x0c, 0x9a, 0xc6, 0x5a, 0xf0,
    0xe8, 0x34, 0x3b, 0x9d, 0x73, 0x01, 0xe0, 0x71, 0xb5, 0x3a, 0x55, 0x9e,
    0xc6, 0xcd, 0xdc, 0xdb, 0x98, 0x29, 0xea, 0x75, 0x4f, 0xf9, 0xa9, 0x5c,
    0xc1, 0x40, 0x1d, 0x7c, 0x7d, 0x60, 0x8f, 0x1e, 0x1d, 0xde, 0xb1, 0x9b,
    0xca, 0x8d, 0x7d, 0x83, 0x09, 0xce, 0x56, 0x94, 0x22, 0x5e, 0xce, 0xa3,
    0x5f, 0x66, 0x3e, 0x24, 0x08, 0x78, 0x05, 0xc1, 0xe2, 0x11, 0x08, 0x0d,
    0x58, 0x1c, 0xec, 0xd3, 0xfd, 0xdb, 0x36, 0x39, 0x74, 0x7d, 0x79, 0xef,
    0xd2, 0x32, 0x99, 0xb2, 0x44, 0xa0, 0x77, 0xf8, 0x88, 0x7e, 0x16, 0x9b,
    0x39, 0x40, 0x48, 0x48, 0x4f, 0x66, 0x26, 0xc9, 0xee, 0x7a, 0xdd, 0xfa,
    0xf8, 0x74, 0xf6, 0xdb, 0xbc, 0x57, 0x5a, 0xc3, 0x4e, 0xd2, 0xb3, 0x5d,
    0xe6, 0xb9, 0x6e, 0x63, 0x72, 0x46, 0xde, 0xe4, 0xff, 0x60, 0x9f, 0x00,
    0x0b, 0x2b, 0x6b, 0xf2, 0xc9, 0x41, 0x0d, 0x0e, 0x99, 0x62, 0xda, 0xeb,
    0x52, 0x5f, 0xfd, 0x37, 0x04, 0xae, 0x56, 0x48, 0x44, 0x6f, 0x2c, 0x86,
    0x06, 0xce, 0x4c, 0x19, 0x84, 0x86, 0x73, 0x0c, 0x9a, 0xb6, 0x89, 0x0e,
    0x42, 0x81, 0xe8, 0xcf, 0x25, 0x3a, 0x4c, 0x3b, 0xd4, 0xaf, 0xec, 0xaf,
    0x99, 0x5c, 0x27, 0x7c, 0x02, 0x4a, 0xdb, 0x1d, 0x52, 0x00, 0x48, 0x4c,
    0x6b, 0x06, 0x9b, 0x2a, 0xaa, 0x38, 0xc0, 0xac, 0x3d, 0xf9, 0xc2, 0x06,
    0x2b, 0x18, 0xc5, 0x48, 0x56, 0x3f, 0xe4, 0xab, 0x5a, 0x2b, 0x3e, 0x87,
    0x3d, 0x29, 0xbb, 0x93, 0x05, 0x6c, 0xcd, 0xaa, 0xd0, 0x0a, 0x13, 0x2f,
    0x96, 0xcd, 0xe4, 0xa8, 0xa4, 0x7b, 0xc1, 0x39, 0x1d, 0x27, 0xc3, 0x20,
    0xa0, 0xc0, 0xe5, 0x05, 0xc6, 0x6e, 0x8e, 0x46, 0x77, 0x46, 0xfb, 0xdc,
    0xbb, 0x1f, 0x3c, 0x6e, 0xc8, 0xd3, 0xdb, 0x02, 0x03, 0x01, 0x00, 0x01,
    0x02, 0x82, 0x01, 0x00, 0x30, 0x00, 0xe5, 0xa5, 0xe1, 0x13, 0x05, 0x78,
    0x3b, 0xf3, 0x84, 0x79, 0x5d, 0x46, 0x24, 0x99, 0x05, 0x61, 0xba, 0x9e,
    0x12, 0xa0, 0x4c, 0xa7, 0xa5, 0x6d, 0x90, 0x1b, 0x3b, 0x0c, 0x8b, 0xc7,
    0xbf, 0x74, 0xe9, 0x1b, 0xc7, 0xb6, 0x13, 0x8c, 0x13, 0x3e, 0x19, 0x86,
    0x9a, 0x85, 0x64, 0xc7, 0xcc, 0xe2, 0xe1, 0x4c, 0xbf, 0xc7, 0x39, 0xf3,
    0x8e, 0x67, 0xbf, 0x59, 0x3c, 0x14, 0x4c, 0xa0, 0xaa, 0xcd, 0x64, 0x75,
    0xe0, 0x3b, 0x32, 0xa2, 0x96, 0x77, 0xfb, 0xb3, 0x57, 0x83, 0x8e, 0xed,
    0xe3, 0x8c, 0x11, 0x06, 0xe6, 0x30, 0x52, 0x29, 0xaf, 0x94, 0x29, 0x9b,
    0x7d, 0xb3, 0x12, 0x78, 0x0e, 0x1a, 0x3e, 0xc1, 0x0a, 0xd1, 0x7b, 0x69,
    0x12, 0xc0, 0xf0, 0x55, 0x1a, 0xf4, 0xed, 0x20, 0x97, 0x2c, 0x6b, 0xb9,
    0x8e, 0x16, 0xab, 0xf5, 0xbd, 0x8e, 0xaa, 0xb5, 0xc4, 0x86, 0x7a, 0x9b,
    0x1d, 0x6f, 0xe3, 0xf8, 0x4f, 0x27, 0xde, 0x5d, 0x05, 0x9a, 0x4d, 0xa6,
    0xd7, 0xb2, 0x18, 0x54, 0xbe, 0x5c, 0x35, 0x4e, 0xb8, 0x62, 0xb5, 0x96,
    0xc8, 0xb3, 0x41, 0xae, 0x74, 0x51, 0x48, 0x45, 0xa1, 0xaa, 0xad, 0x64,
    0x3d, 0x2a, 0x78, 0xd0, 0xf4, 0x49, 0xcb, 0xd5, 0x24, 0x56, 0x23, 0x48,
    0x42, 0x20, 0x3f, 0xbe, 0x03, 0x91, 0xc1, 0xb8, 0x1a, 0xcc, 0x26, 0x0b,
    0xdc, 0x9f, 0x24, 0x75, 0x12, 0xf8, 0xd5, 0x0c, 0xbc, 0x84, 0xdc, 0x7a,
    0x94, 0xb8, 0x9d, 0x3a, 0x3c, 0x0e, 0xcf, 0x06, 0xfc, 0xf1, 0xe4, 0xf8,
    0x46, 0xc3, 0xa0, 0x8f, 0x09, 0x0d, 0xbc, 0xcc, 0x15, 0x0c, 0x4e, 0x92,
    0x21, 0xe6, 0x45, 0x5a, 0x5e, 0xe0, 0xbe, 0x8d, 0xab, 0x1d, 0x3c, 0x32,
    0xa7, 0x7c, 0x36, 0xda, 0xc9, 0x5a, 0xae, 0xd1, 0xf1, 0x0f, 0x4c, 0x2f,
    0xbf, 0x57, 0x0d, 0x7c, 0x70, 0x3a, 0x71, 0x11, 0x02, 0x81, 0x81, 0x00,
    0xfd, 0x50, 0xa3, 0xb7, 0x52, 0xfa, 0x64, 0x84, 0x50, 0x1a, 0x35, 0x8c,
    0xe0, 0xe9, 0x23, 0x8a, 0x47, 0xdb, 0x99, 0x4a, 0xa4, 0x22, 0xff, 0xa6,
    0x30, 0x03, 0x38, 0x2e, 0x11, 0x99, 0xeb, 0x27, 0x45, 0x96, 0x2f, 0xb6,
    0xae, 0x28, 0x82, 0xad, 0x32, 0xbd, 0x9a, 0xf8, 0xd2, 0x2c, 0xea, 0xe0,
    0x49, 0xd2, 0x3c, 0x17, 0x92, 0xf0, 0xe1, 0x0b, 0xb4, 0xec, 0xfd, 0xf2,
    0xac, 0x76, 0xa5, 0xf5, 0x89, 0x91, 0xe7, 0x0c, 0x7b, 0xe4, 0x5a, 0x02,
    0x88, 0xf9, 0xf7, 0x10, 0x40, 0x3b, 0x0a, 0x12, 0x83, 0x5c, 0x4b, 0x62,
    0x7b, 0xdb, 0xbe, 0x7f, 0x6b, 0x44, 0x81, 0xaa, 0xab, 0x6a, 0x2f, 0x72,
    0xf2, 0x72, 0xa2, 0x84, 0x3a, 0x6a, 0x38, 0x7b, 0x03, 0x16, 0x77, 0x4b,
    0xd8, 0x41, 0x44, 0xfe, 0xcb, 0xb1, 0x3c, 0x4c, 0x96, 0x1c, 0x01, 0x75,
    0x00, 0x09, 0xa2, 0xae, 0xe5, 0x7c, 0x1b, 0xff, 0x02, 0x81, 0x81, 0x00,
    0xc6, 0xee, 0xeb, 0x24, 0x69, 0x78, 0xda, 0x36, 0x9a, 0xb0, 0xf9, 0x11,
    0x57, 0xc3, 0x5a, 0x63, 0xa4, 0x57, 0x50, 0xc7, 0x1e, 0xf7, 0x46, 0xd0,
    0xa7, 0xac, 0x58, 0x9c, 0xdc, 0x93, 0x6d, 0x57, 0x78, 0xb7, 0x76, 0x88,
    0x65, 0x2f, 0x13, 0xb6, 0x8c, 0x2e, 0xb9, 0x73, 0xc4, 0x33, 0x63, 0x8e,
    0x70, 0xfb, 0x79, 0x68, 0x0d, 0x76, 0xf2, 0x6a, 0x01, 0x65, 0x07, 0x13,
    0x5d, 0x14, 0x4c, 0xd8, 0x62, 0x2d, 0x7e, 0xa0, 0x13, 0xbf, 0x94, 0x28,
    0xee, 0xb5, 0x60, 0x94, 0x8e, 0xfe, 0x4b, 0xdd, 0x6e, 0xef, 0xf8, 0xe0,
    0x80, 0x71, 0x18, 0x69, 0x44, 0xab, 0x74, 0xed, 0x36, 0x2c, 0x5a, 0xfc,
    0xc0, 0x5a, 0xbd, 0x21, 0x61, 0x44, 0x65, 0x31, 0x9e, 0x00, 0x2a, 0x3c,
    0x99, 0x06, 0x9c, 0x4d, 0xc3, 0x97, 0x09, 0x1c, 0xc0, 0xd5, 0xd2, 0x4e,
    0xf7, 0x7e, 0xa1, 0xd1, 0xa6, 0x47, 0x38, 0x25, 0x02, 0x81, 0x80, 0x01,
    0x4f, 0x70, 0x79, 0x5b, 0x49, 0x86, 0x49, 0x94, 0xec, 0x7d, 0xc8, 0x6b,
    0xc5, 0x68, 0xf4, 0xa7, 0x28, 0x80, 0xa3, 0x7d, 0x33, 0xdd, 0x24, 0xab,
    0xec, 0xe8, 0x56, 0x7c, 0xaa, 0xd2, 0x27, 0x92, 0xd9, 0x93, 0x07, 0x9b,
    0xe1, 0x03, 0xc4, 0x07, 0x96, 0x29, 0x7e, 0x0e, 0x00, 0x43, 0x7a, 0xc3,
    0x86, 0xfd, 0xde, 0x95, 0x58, 0xff, 0xa1, 0x02, 0xdf, 0x92, 0xf4, 0xb5,
    0x65, 0xab, 0xb8, 0x18, 0x6d, 0x13, 0xc7, 0xe1, 0xc0, 0x2d, 0xa3, 0x03,
    0xb8, 0x5f, 0x49, 0xcb, 0x3b, 0x42, 0xf3, 0x13, 0x90, 0xdf, 0xa6, 0xf3,
    0xc3, 0x10, 0x3a, 0x32, 0x80, 0xd9, 0x36, 0xdb, 0xca, 0x21, 0xd2, 0xb3,
    0x64, 0x5a, 0x68, 0xda, 0xb0, 0x7f, 0xf8, 0x4a, 0xec, 0xcb, 0xd3, 0x2d,
    0x9c, 0x30, 0xd2, 0x2c, 0x95, 0x8f, 0x1d, 0x4a, 0x4d, 0x7c, 0xc8, 0x71,
    0x26, 0x9b, 0x9b, 0xd1, 0xfe, 0x11, 0x5b, 0x02, 0x81, 0x80, 0x22, 0x7a,
    0xc0, 0x98, 0xc4, 0x0b, 0x25, 0x4f, 0x37, 0x8a, 0x9a, 0xf0, 0xcd, 0x94,
    0x57, 0x73, 0x53, 0xc5, 0xaa, 0x83, 0x88, 0xb3, 0x75, 0x3b, 0xaf, 0x04,
    0x29, 0x2b, 0xae, 0xf3, 0x82, 0x8d, 0x19, 0xa8, 0x3a, 0xcc, 0x33, 0x35,
    0x70, 0xa6, 0x40, 0x2f, 0xcd, 0x06, 0xea, 0xa7, 0xb9, 0x86, 0xb3, 0xc0,
    0x72, 0x6f, 0x7d, 0x7d, 0xf3, 0x50, 0x3a, 0x43, 0xa7, 0x71, 0x4c, 0xbd,
    0xba, 0xff, 0xfa, 0x2c, 0x46, 0x79, 0x3a, 0x53, 0x07, 0x3b, 0xfc, 0xfb,
    0xc4, 0xec, 0x9a, 0xc8, 0x2a, 0xa0, 0x0b, 0x9d, 0x5e, 0x36, 0x93, 0x2c,
    0x86, 0xfd, 0x9f, 0xe0, 0x53, 0xd8, 0xd5, 0x7d, 0xe4, 0x9b, 0x50, 0x3f,
    0xa9, 0xee, 0x42, 0x2c, 0x97, 0x99, 0x7c, 0xf8, 0x2c, 0x59, 0xea, 0x70,
    0x01, 0xe1, 0x5c, 0x98, 0x2e, 0x05, 0x24, 0xcb, 0x2a, 0xb3, 0x73, 0x24,
    0x28, 0xa9, 0xec, 0xb7, 0x05, 0x5d, 0x02, 0x81, 0x80, 0x51, 0x25, 0xc5,
    0xc4, 0x8c, 0xa1, 0xdc, 0x5a, 0x7f, 0xf2, 0xe3, 0xf7, 0x3f, 0xb8, 0x10,
    0x6e, 0xea, 0x71, 0x19, 0x24, 0x58, 0x85, 0xb8, 0x08, 0x06, 0x66, 0x86,
    0x70, 0x7f, 0xcb, 0x0e, 0xe4, 0xa8, 0xd8, 0x20, 0xf3, 0xd2, 0xa8, 0xaa,
    0xac, 0xe6, 0x31, 0x05, 0x91, 0x46, 0x23, 0xe3, 0xb9, 0x1c, 0xb8, 0x5e,
    0x46, 0x4f, 0xc6, 0x28, 0x13, 0x3f, 0xa6, 0xd5, 0x43, 0xe5, 0xa0, 0xab,
    0xa2, 0xce, 0xa9, 0x62, 0x6c, 0x39, 0x93, 0x75, 0x7b, 0xdc, 0x98, 0x36,
    0xec, 0x7c, 0x83, 0x27, 0xbe, 0x39, 0x99, 0x1d, 0xce, 0x44, 0x28, 0xcf,
    0xc0, 0xeb, 0xa8, 0x37, 0x3b, 0x5f, 0xbc, 0x8c, 0x4e, 0x96, 0x25, 0x5c,
    0x1e, 0xb1, 0x35, 0x33, 0x2f, 0xfd, 0x55, 0x32, 0x9b, 0xd3, 0xdd, 0x1d,
    0xe1, 0x8a, 0x4b, 0x1f, 0xf9, 0xd4, 0x0a, 0xa9, 0xf7, 0xdc, 0xae, 0x75,
    0x85, 0x32, 0x66, 0xed, 0x53};

// kExampleECKeyDER is a sample EC private key encoded as an ECPrivateKey
// structure.
static const uint8_t kExampleECKeyDER[] = {
    0x30, 0x77, 0x02, 0x01, 0x01, 0x04, 0x20, 0x07, 0x0f, 0x08, 0x72, 0x7a,
    0xd4, 0xa0, 0x4a, 0x9c, 0xdd, 0x59, 0xc9, 0x4d, 0x89, 0x68, 0x77, 0x08,
    0xb5, 0x6f, 0xc9, 0x5d, 0x30, 0x77, 0x0e, 0xe8, 0xd1, 0xc9, 0xce, 0x0a,
    0x8b, 0xb4, 0x6a, 0xa0, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d,
    0x03, 0x01, 0x07, 0xa1, 0x44, 0x03, 0x42, 0x00, 0x04, 0xe6, 0x2b, 0x69,
    0xe2, 0xbf, 0x65, 0x9f, 0x97, 0xbe, 0x2f, 0x1e, 0x0d, 0x94, 0x8a, 0x4c,
    0xd5, 0x97, 0x6b, 0xb7, 0xa9, 0x1e, 0x0d, 0x46, 0xfb, 0xdd, 0xa9, 0xa9,
    0x1e, 0x9d, 0xdc, 0xba, 0x5a, 0x01, 0xe7, 0xd6, 0x97, 0xa8, 0x0a, 0x18,
    0xf9, 0xc3, 0xc4, 0xa3, 0x1e, 0x56, 0xe2, 0x7c, 0x83, 0x48, 0xdb, 0x16,
    0x1a, 0x1c, 0xf5, 0x1d, 0x7e, 0xf1, 0x94, 0x2d, 0x4b, 0xcf, 0x72, 0x22,
    0xc1,
};

// kExampleECKeyPKCS8 is a sample EC private key encoded as a PKCS#8
// PrivateKeyInfo.
static const uint8_t kExampleECKeyPKCS8[] = {
    0x30, 0x81, 0x87, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86,
    0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d,
    0x03, 0x01, 0x07, 0x04, 0x6d, 0x30, 0x6b, 0x02, 0x01, 0x01, 0x04, 0x20,
    0x43, 0x09, 0xc0, 0x67, 0x75, 0x21, 0x47, 0x9d, 0xa8, 0xfa, 0x16, 0xdf,
    0x15, 0x73, 0x61, 0x34, 0x68, 0x6f, 0xe3, 0x8e, 0x47, 0x91, 0x95, 0xab,
    0x79, 0x4a, 0x72, 0x14, 0xcb, 0xe2, 0x49, 0x4f, 0xa1, 0x44, 0x03, 0x42,
    0x00, 0x04, 0xde, 0x09, 0x08, 0x07, 0x03, 0x2e, 0x8f, 0x37, 0x9a, 0xd5,
    0xad, 0xe5, 0xc6, 0x9d, 0xd4, 0x63, 0xc7, 0x4a, 0xe7, 0x20, 0xcb, 0x90,
    0xa0, 0x1f, 0x18, 0x18, 0x72, 0xb5, 0x21, 0x88, 0x38, 0xc0, 0xdb, 0xba,
    0xf6, 0x99, 0xd8, 0xa5, 0x3b, 0x83, 0xe9, 0xe3, 0xd5, 0x61, 0x99, 0x73,
    0x42, 0xc6, 0x6c, 0xe8, 0x0a, 0x95, 0x40, 0x41, 0x3b, 0x0d, 0x10, 0xa7,
    0x4a, 0x93, 0xdb, 0x5a, 0xe7, 0xec,
};

// kExampleECKeySpecifiedCurvePKCS8 is a sample EC private key encoded as a
// PKCS#8 PrivateKeyInfo with P-256's parameters spelled out rather than using
// the curve OID.
static const uint8_t kExampleECKeySpecifiedCurvePKCS8[] = {
    0x30, 0x82, 0x01, 0x79, 0x02, 0x01, 0x00, 0x30, 0x82, 0x01, 0x03, 0x06,
    0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x30, 0x81, 0xf7, 0x02,
    0x01, 0x01, 0x30, 0x2c, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x01,
    0x01, 0x02, 0x21, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    0x30, 0x5b, 0x04, 0x20, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc,
    0x04, 0x20, 0x5a, 0xc6, 0x35, 0xd8, 0xaa, 0x3a, 0x93, 0xe7, 0xb3, 0xeb,
    0xbd, 0x55, 0x76, 0x98, 0x86, 0xbc, 0x65, 0x1d, 0x06, 0xb0, 0xcc, 0x53,
    0xb0, 0xf6, 0x3b, 0xce, 0x3c, 0x3e, 0x27, 0xd2, 0x60, 0x4b, 0x03, 0x15,
    0x00, 0xc4, 0x9d, 0x36, 0x08, 0x86, 0xe7, 0x04, 0x93, 0x6a, 0x66, 0x78,
    0xe1, 0x13, 0x9d, 0x26, 0xb7, 0x81, 0x9f, 0x7e, 0x90, 0x04, 0x41, 0x04,
    0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47, 0xf8, 0xbc, 0xe6, 0xe5,
    0x63, 0xa4, 0x40, 0xf2, 0x77, 0x03, 0x7d, 0x81, 0x2d, 0xeb, 0x33, 0xa0,
    0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96, 0x4f, 0xe3, 0x42, 0xe2,
    0xfe, 0x1a, 0x7f, 0x9b, 0x8e, 0xe7, 0xeb, 0x4a, 0x7c, 0x0f, 0x9e, 0x16,
    0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31, 0x5e, 0xce, 0xcb, 0xb6, 0x40, 0x68,
    0x37, 0xbf, 0x51, 0xf5, 0x02, 0x21, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
    0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbc,
    0xe6, 0xfa, 0xad, 0xa7, 0x17, 0x9e, 0x84, 0xf3, 0xb9, 0xca, 0xc2, 0xfc,
    0x63, 0x25, 0x51, 0x02, 0x01, 0x01, 0x04, 0x6d, 0x30, 0x6b, 0x02, 0x01,
    0x01, 0x04, 0x20, 0x43, 0x09, 0xc0, 0x67, 0x75, 0x21, 0x47, 0x9d, 0xa8,
    0xfa, 0x16, 0xdf, 0x15, 0x73, 0x61, 0x34, 0x68, 0x6f, 0xe3, 0x8e, 0x47,
    0x91, 0x95, 0xab, 0x79, 0x4a, 0x72, 0x14, 0xcb, 0xe2, 0x49, 0x4f, 0xa1,
    0x44, 0x03, 0x42, 0x00, 0x04, 0xde, 0x09, 0x08, 0x07, 0x03, 0x2e, 0x8f,
    0x37, 0x9a, 0xd5, 0xad, 0xe5, 0xc6, 0x9d, 0xd4, 0x63, 0xc7, 0x4a, 0xe7,
    0x20, 0xcb, 0x90, 0xa0, 0x1f, 0x18, 0x18, 0x72, 0xb5, 0x21, 0x88, 0x38,
    0xc0, 0xdb, 0xba, 0xf6, 0x99, 0xd8, 0xa5, 0x3b, 0x83, 0xe9, 0xe3, 0xd5,
    0x61, 0x99, 0x73, 0x42, 0xc6, 0x6c, 0xe8, 0x0a, 0x95, 0x40, 0x41, 0x3b,
    0x0d, 0x10, 0xa7, 0x4a, 0x93, 0xdb, 0x5a, 0xe7, 0xec,
};

// kExampleBadECKeyDER is a sample EC private key encoded as an ECPrivateKey
// structure. The private key is equal to the order and will fail to import.
static const uint8_t kExampleBadECKeyDER[] = {
    0x30, 0x66, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48,
    0xCE, 0x3D, 0x02, 0x01, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03,
    0x01, 0x07, 0x04, 0x4C, 0x30, 0x4A, 0x02, 0x01, 0x01, 0x04, 0x20, 0xFF,
    0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xBC, 0xE6, 0xFA, 0xAD, 0xA7, 0x17, 0x9E, 0x84, 0xF3,
    0xB9, 0xCA, 0xC2, 0xFC, 0x63, 0x25, 0x51, 0xA1, 0x23, 0x03, 0x21, 0x00,
    0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xBC, 0xE6, 0xFA, 0xAD, 0xA7, 0x17, 0x9E, 0x84,
    0xF3, 0xB9, 0xCA, 0xC2, 0xFC, 0x63, 0x25, 0x51
};

// kExampleBadECKeyDER2 is a sample EC private key encoded as an ECPrivateKey
// structure, but with the curve OID swapped out for 1.1.1.1.1.1.1.1.1. It is
// then concatenated with an ECPrivateKey wrapped in a PrivateKeyInfo,
// optional public key omitted, and with the private key chopped off.
static const uint8_t kExampleBadECKeyDER2[] = {
    0x30, 0x77, 0x02, 0x01, 0x01, 0x04, 0x20, 0x07, 0x0f, 0x08, 0x72, 0x7a,
    0xd4, 0xa0, 0x4a, 0x9c, 0xdd, 0x59, 0xc9, 0x4d, 0x89, 0x68, 0x77, 0x08,
    0xb5, 0x6f, 0xc9, 0x5d, 0x30, 0x77, 0x0e, 0xe8, 0xd1, 0xc9, 0xce, 0x0a,
    0x8b, 0xb4, 0x6a, 0xa0, 0x0a, 0x06, 0x08, 0x29, 0x01, 0x01, 0x01, 0x01,
    0x01, 0x01, 0x01, 0xa1, 0x44, 0x03, 0x42, 0x00, 0x04, 0xe6, 0x2b, 0x69,
    0xe2, 0xbf, 0x65, 0x9f, 0x97, 0xbe, 0x2f, 0x1e, 0x0d, 0x94, 0x8a, 0x4c,
    0xd5, 0x97, 0x6b, 0xb7, 0xa9, 0x1e, 0x0d, 0x46, 0xfb, 0xdd, 0xa9, 0xa9,
    0x1e, 0x9d, 0xdc, 0xba, 0x5a, 0x01, 0xe7, 0xd6, 0x97, 0xa8, 0x0a, 0x18,
    0xf9, 0xc3, 0xc4, 0xa3, 0x1e, 0x56, 0xe2, 0x7c, 0x83, 0x48, 0xdb, 0x16,
    0x1a, 0x1c, 0xf5, 0x1d, 0x7e, 0xf1, 0x94, 0x2d, 0x4b, 0xcf, 0x72, 0x22,
    0xc1, 0x30, 0x41, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86,
    0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d,
    0x03, 0x01, 0x07, 0x04, 0x27, 0x30, 0x25, 0x02, 0x01, 0x01, 0x04, 0x20,
    0x07,
};

// kInvalidPrivateKey is an invalid private key. See
// https://rt.openssl.org/Ticket/Display.html?id=4131.
static const uint8_t kInvalidPrivateKey[] = {
    0x30, 0x39, 0x02, 0x01, 0x02, 0x30, 0x09, 0x06, 0x01, 0x38, 0x08,
    0x04, 0x69, 0x30, 0x30, 0x80, 0x30, 0x19, 0x01, 0x02, 0x9f, 0xf8,
    0x8b, 0x29, 0x80, 0x30, 0xb0, 0x1b, 0x06, 0x09, 0x22, 0xbe, 0x08,
    0x04, 0xe9, 0x30, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x3a, 0x01, 0x80,
    0x09, 0x30, 0x80, 0x06, 0x01, 0x02, 0x30, 0x80, 0x30, 0x01, 0x3b,
    0x02, 0x00, 0x00, 0x04, 0x20, 0x30, 0x82, 0x04, 0xe9, 0x30, 0xc3,
    0xe8, 0x30, 0x01, 0x05, 0x30, 0x80, 0x30, 0x01, 0x3b, 0x01, 0x04,
    0x02, 0x02, 0xff, 0x00, 0x30, 0x29, 0x02, 0x11, 0x03, 0x29, 0x29,
    0x02, 0x00, 0x99, 0x30, 0x80, 0x06, 0x21, 0x02, 0x24, 0x04, 0xe8,
    0x30, 0x01, 0x01, 0x04, 0x30, 0x80, 0x1b, 0x06, 0x09, 0x2a, 0x86,
    0x48, 0x30, 0x01, 0xaa, 0x02, 0x86, 0xc0, 0x30, 0xdf, 0xe9, 0x80,
};

// kExampleMLDSA65KeyDER is a ML-DSA private key in ASN.1, DER format.
// Of course, you should never use this key anywhere but in an example.
static const uint8_t kExampleMLDSA65KeyDER[] = {
    0x30, 0x82, 0x0F, 0xD8, 0x02, 0x01, 0x00, 0x30, 0x0B, 0x06, 0x09, 0x60,
    0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x12, 0x04, 0x82, 0x0F, 0xC4,
    0x04, 0x82, 0x0F, 0xC0, 0x48, 0x68, 0x3D, 0x91, 0x97, 0x8E, 0x31, 0xEB,
    0x3D, 0xDD, 0xB8, 0xB0, 0x47, 0x34, 0x82, 0xD2, 0xB8, 0x8A, 0x5F, 0x62,
    0x59, 0x49, 0xFD, 0x8F, 0x58, 0xA5, 0x61, 0xE6, 0x96, 0xBD, 0x4C, 0x27,
    0xD8, 0x53, 0xFA, 0x69, 0xB8, 0x19, 0x90, 0x23, 0xE8, 0xCD, 0x67, 0x8D,
    0xD9, 0xFA, 0xBF, 0x90, 0x47, 0x64, 0x6F, 0xFD, 0x0C, 0xB3, 0xCC, 0x7F,
    0x79, 0x58, 0x05, 0xA7, 0x1E, 0x70, 0xD2, 0x37, 0x1B, 0x05, 0x63, 0xE3,
    0xCD, 0x33, 0x46, 0x14, 0x9C, 0x8C, 0x9E, 0xBC, 0xF2, 0x3B, 0x0A, 0x4E,
    0x5A, 0x90, 0x0E, 0xEA, 0x9C, 0x65, 0x62, 0x79, 0x0A, 0x7C, 0x63, 0xE3,
    0x86, 0x63, 0xDA, 0xA2, 0xDD, 0xDB, 0x6E, 0x48, 0x0D, 0xC4, 0x05, 0xA1,
    0xE7, 0x01, 0x94, 0x8B, 0x74, 0x84, 0x1E, 0xF5, 0xCC, 0x1C, 0x3F, 0x2B,
    0xF3, 0x27, 0x97, 0x2E, 0x95, 0x10, 0x51, 0x0C, 0xD5, 0x37, 0x5E, 0xCC,
    0x08, 0x55, 0x71, 0x77, 0x11, 0x87, 0x22, 0x21, 0x86, 0x23, 0x81, 0x00,
    0x04, 0x24, 0x77, 0x80, 0x61, 0x47, 0x50, 0x07, 0x50, 0x17, 0x17, 0x03,
    0x55, 0x04, 0x51, 0x51, 0x25, 0x47, 0x18, 0x38, 0x04, 0x61, 0x75, 0x72,
    0x22, 0x44, 0x10, 0x88, 0x68, 0x60, 0x86, 0x46, 0x01, 0x27, 0x47, 0x56,
    0x71, 0x80, 0x87, 0x06, 0x66, 0x86, 0x43, 0x32, 0x44, 0x41, 0x22, 0x04,
    0x36, 0x38, 0x66, 0x75, 0x02, 0x82, 0x36, 0x34, 0x24, 0x43, 0x22, 0x05,
    0x73, 0x64, 0x10, 0x64, 0x55, 0x54, 0x77, 0x22, 0x75, 0x56, 0x81, 0x43,
    0x36, 0x14, 0x62, 0x55, 0x08, 0x20, 0x64, 0x37, 0x68, 0x54, 0x68, 0x75,
    0x43, 0x53, 0x75, 0x10, 0x68, 0x71, 0x83, 0x33, 0x80, 0x54, 0x75, 0x05,
    0x25, 0x80, 0x75, 0x28, 0x18, 0x84, 0x38, 0x11, 0x08, 0x72, 0x60, 0x20,
    0x20, 0x08, 0x58, 0x83, 0x01, 0x83, 0x61, 0x13, 0x82, 0x82, 0x12, 0x06,
    0x17, 0x11, 0x57, 0x87, 0x68, 0x78, 0x88, 0x78, 0x64, 0x37, 0x54, 0x60,
    0x16, 0x57, 0x15, 0x50, 0x84, 0x71, 0x88, 0x66, 0x07, 0x27, 0x32, 0x88,
    0x06, 0x64, 0x74, 0x18, 0x56, 0x76, 0x21, 0x80, 0x31, 0x82, 0x76, 0x64,
    0x15, 0x78, 0x24, 0x50, 0x25, 0x64, 0x66, 0x43, 0x11, 0x35, 0x04, 0x36,
    0x47, 0x80, 0x12, 0x66, 0x73, 0x14, 0x30, 0x11, 0x66, 0x06, 0x55, 0x86,
    0x47, 0x18, 0x36, 0x88, 0x63, 0x50, 0x38, 0x47, 0x86, 0x11, 0x01, 0x20,
    0x23, 0x56, 0x11, 0x61, 0x37, 0x86, 0x07, 0x85, 0x32, 0x12, 0x40, 0x07,
    0x54, 0x78, 0x82, 0x30, 0x43, 0x66, 0x61, 0x16, 0x60, 0x42, 0x55, 0x41,
    0x82, 0x85, 0x60, 0x53, 0x67, 0x78, 0x56, 0x38, 0x43, 0x44, 0x30, 0x63,
    0x26, 0x10, 0x77, 0x07, 0x31, 0x78, 0x42, 0x72, 0x14, 0x11, 0x16, 0x53,
    0x03, 0x85, 0x27, 0x68, 0x67, 0x46, 0x01, 0x50, 0x82, 0x37, 0x35, 0x32,
    0x07, 0x66, 0x10, 0x75, 0x04, 0x68, 0x12, 0x48, 0x06, 0x66, 0x03, 0x03,
    0x26, 0x52, 0x31, 0x24, 0x45, 0x40, 0x88, 0x00, 0x31, 0x80, 0x88, 0x76,
    0x72, 0x17, 0x30, 0x71, 0x82, 0x47, 0x21, 0x51, 0x27, 0x80, 0x11, 0x65,
    0x44, 0x74, 0x86, 0x61, 0x72, 0x23, 0x33, 0x80, 0x86, 0x60, 0x64, 0x46,
    0x83, 0x52, 0x15, 0x84, 0x20, 0x36, 0x80, 0x11, 0x80, 0x21, 0x18, 0x18,
    0x33, 0x17, 0x73, 0x54, 0x53, 0x48, 0x81, 0x00, 0x44, 0x86, 0x53, 0x67,
    0x43, 0x70, 0x57, 0x72, 0x58, 0x83, 0x34, 0x60, 0x38, 0x42, 0x32, 0x85,
    0x68, 0x10, 0x06, 0x04, 0x26, 0x04, 0x25, 0x84, 0x56, 0x02, 0x35, 0x68,
    0x20, 0x51, 0x83, 0x86, 0x38, 0x43, 0x24, 0x21, 0x22, 0x42, 0x45, 0x64,
    0x58, 0x58, 0x67, 0x71, 0x45, 0x72, 0x85, 0x04, 0x78, 0x87, 0x17, 0x18,
    0x06, 0x18, 0x83, 0x60, 0x86, 0x86, 0x41, 0x56, 0x50, 0x81, 0x16, 0x50,
    0x26, 0x46, 0x70, 0x06, 0x08, 0x26, 0x62, 0x27, 0x38, 0x31, 0x72, 0x40,
    0x72, 0x57, 0x30, 0x07, 0x27, 0x28, 0x86, 0x20, 0x66, 0x75, 0x88, 0x68,
    0x26, 0x07, 0x06, 0x40, 0x20, 0x33, 0x03, 0x43, 0x66, 0x31, 0x55, 0x46,
    0x42, 0x45, 0x34, 0x56, 0x67, 0x18, 0x73, 0x45, 0x65, 0x83, 0x70, 0x22,
    0x50, 0x84, 0x68, 0x56, 0x28, 0x80, 0x70, 0x36, 0x70, 0x84, 0x62, 0x37,
    0x17, 0x10, 0x06, 0x57, 0x17, 0x58, 0x47, 0x78, 0x70, 0x86, 0x55, 0x53,
    0x78, 0x22, 0x35, 0x14, 0x46, 0x77, 0x28, 0x56, 0x73, 0x03, 0x22, 0x87,
    0x00, 0x14, 0x33, 0x20, 0x61, 0x71, 0x58, 0x45, 0x52, 0x66, 0x32, 0x50,
    0x26, 0x51, 0x33, 0x47, 0x77, 0x38, 0x03, 0x55, 0x16, 0x43, 0x13, 0x47,
    0x35, 0x10, 0x66, 0x27, 0x51, 0x75, 0x74, 0x02, 0x46, 0x88, 0x81, 0x70,
    0x67, 0x43, 0x46, 0x81, 0x86, 0x01, 0x76, 0x52, 0x45, 0x33, 0x30, 0x87,
    0x21, 0x04, 0x34, 0x34, 0x01, 0x03, 0x22, 0x87, 0x63, 0x51, 0x55, 0x26,
    0x50, 0x81, 0x30, 0x77, 0x45, 0x44, 0x41, 0x68, 0x15, 0x41, 0x83, 0x63,
    0x64, 0x11, 0x20, 0x40, 0x26, 0x87, 0x30, 0x43, 0x67, 0x77, 0x12, 0x80,
    0x88, 0x46, 0x35, 0x54, 0x53, 0x00, 0x62, 0x45, 0x81, 0x04, 0x58, 0x36,
    0x51, 0x24, 0x84, 0x27, 0x80, 0x34, 0x51, 0x66, 0x63, 0x58, 0x43, 0x78,
    0x56, 0x01, 0x46, 0x51, 0x15, 0x74, 0x23, 0x21, 0x43, 0x66, 0x85, 0x22,
    0x47, 0x77, 0x31, 0x34, 0x50, 0x17, 0x83, 0x62, 0x42, 0x05, 0x50, 0x00,
    0x64, 0x84, 0x47, 0x12, 0x34, 0x40, 0x88, 0x00, 0x60, 0x47, 0x35, 0x40,
    0x57, 0x83, 0x33, 0x63, 0x08, 0x21, 0x06, 0x15, 0x22, 0x52, 0x07, 0x24,
    0x88, 0x51, 0x34, 0x86, 0x37, 0x06, 0x76, 0x22, 0x58, 0x85, 0x71, 0x26,
    0x56, 0x73, 0x47, 0x68, 0x16, 0x46, 0x46, 0x84, 0x25, 0x87, 0x08, 0x12,
    0x27, 0x05, 0x50, 0x08, 0x38, 0x32, 0x00, 0x23, 0x20, 0x80, 0x66, 0x34,
    0x53, 0x36, 0x00, 0x33, 0x46, 0x85, 0x72, 0x47, 0x06, 0x35, 0x54, 0x00,
    0x35, 0x77, 0x12, 0x27, 0x52, 0x30, 0x71, 0x42, 0x53, 0x68, 0x74, 0x37,
    0x45, 0x70, 0x05, 0x66, 0x43, 0x22, 0x44, 0x82, 0x85, 0x20, 0x72, 0x18,
    0x33, 0x30, 0x20, 0x53, 0x37, 0x33, 0x40, 0x77, 0x27, 0x80, 0x55, 0x25,
    0x30, 0x63, 0x52, 0x50, 0x40, 0x67, 0x33, 0x46, 0x13, 0x18, 0x07, 0x28,
    0x07, 0x17, 0x24, 0x83, 0x77, 0x63, 0x45, 0x73, 0x18, 0x58, 0x51, 0x60,
    0x23, 0x33, 0x44, 0x36, 0x25, 0x16, 0x43, 0x38, 0x16, 0x08, 0x58, 0x77,
    0x34, 0x62, 0x42, 0x88, 0x30, 0x07, 0x03, 0x65, 0x85, 0x37, 0x55, 0x00,
    0x75, 0x52, 0x31, 0x50, 0x37, 0x02, 0x13, 0x24, 0x63, 0x04, 0x37, 0x08,
    0x68, 0x06, 0x36, 0x15, 0x03, 0x03, 0x00, 0x43, 0x58, 0x63, 0x57, 0x08,
    0x02, 0x11, 0x06, 0x64, 0x73, 0x46, 0x35, 0x22, 0x62, 0x03, 0x30, 0x43,
    0x80, 0x21, 0x08, 0x52, 0x87, 0x57, 0x83, 0x21, 0x07, 0x88, 0x67, 0x48,
    0x08, 0x56, 0x34, 0x74, 0x36, 0x73, 0x42, 0x84, 0x05, 0x84, 0x66, 0x84,
    0x14, 0x37, 0x00, 0x55, 0x10, 0x87, 0x34, 0x26, 0x44, 0x77, 0x21, 0x12,
    0x73, 0x84, 0x73, 0x65, 0x26, 0x47, 0x25, 0x77, 0x14, 0x47, 0x04, 0x17,
    0x86, 0x44, 0x26, 0x02, 0x47, 0x11, 0x87, 0x40, 0x81, 0x22, 0x16, 0x60,
    0x58, 0x47, 0x17, 0x81, 0x37, 0x06, 0x76, 0x80, 0x81, 0x70, 0x58, 0x18,
    0x55, 0x85, 0x47, 0x13, 0x63, 0x42, 0x10, 0x75, 0x58, 0x01, 0x63, 0x58,
    0x35, 0x85, 0x18, 0x44, 0x03, 0x84, 0x71, 0x10, 0x33, 0x87, 0x42, 0x62,
    0x82, 0x47, 0x74, 0x13, 0x65, 0x54, 0x42, 0x70, 0x73, 0x46, 0x35, 0x77,
    0x75, 0x00, 0x66, 0x25, 0x62, 0x68, 0x42, 0x02, 0x12, 0x46, 0x83, 0x86,
    0x46, 0x16, 0x64, 0x60, 0x31, 0x22, 0x53, 0x88, 0x84, 0x54, 0x00, 0x84,
    0x57, 0x34, 0x46, 0x47, 0x54, 0x47, 0x25, 0x60, 0x54, 0x61, 0x66, 0x84,
    0x66, 0x30, 0x88, 0x06, 0x38, 0x27, 0x15, 0x63, 0x28, 0x71, 0x83, 0x84,
    0x06, 0x52, 0x24, 0x76, 0x81, 0x16, 0x06, 0x62, 0x13, 0x03, 0x30, 0x18,
    0x68, 0x02, 0x80, 0x13, 0x84, 0x63, 0x05, 0x05, 0x65, 0x72, 0x38, 0x75,
    0x83, 0x65, 0x72, 0x32, 0x30, 0x68, 0x80, 0x46, 0x12, 0x26, 0x06, 0x65,
    0x16, 0x75, 0x57, 0x05, 0x32, 0x41, 0x32, 0x27, 0x67, 0x35, 0x17, 0x08,
    0x01, 0x53, 0x00, 0x16, 0x28, 0x46, 0x01, 0x34, 0x88, 0x77, 0x01, 0x11,
    0x88, 0x15, 0x57, 0x13, 0x15, 0x46, 0x43, 0x11, 0x70, 0x47, 0x32, 0x88,
    0x28, 0x56, 0x36, 0x82, 0x34, 0x55, 0x50, 0x41, 0x86, 0x27, 0x65, 0x63,
    0x11, 0x11, 0x68, 0x75, 0x05, 0x10, 0x42, 0x54, 0x41, 0x44, 0x27, 0x85,
    0x22, 0x11, 0x17, 0x17, 0x88, 0x15, 0x36, 0x85, 0x15, 0x74, 0x47, 0x16,
    0x62, 0x55, 0x36, 0x55, 0x83, 0x63, 0x02, 0x50, 0x28, 0x55, 0x76, 0x87,
    0x53, 0x27, 0x13, 0x71, 0x03, 0x72, 0x37, 0x05, 0x71, 0x47, 0x61, 0x71,
    0x36, 0x51, 0x84, 0x12, 0x42, 0x36, 0x64, 0x44, 0x66, 0x41, 0x43, 0x52,
    0x05, 0x21, 0x08, 0x51, 0x57, 0x03, 0x33, 0x63, 0x86, 0x02, 0x58, 0x42,
    0x66, 0x28, 0x14, 0x81, 0x10, 0x54, 0x62, 0x68, 0x17, 0x30, 0x38, 0x75,
    0x64, 0x33, 0x21, 0x65, 0x88, 0x56, 0x86, 0x63, 0x63, 0x28, 0x13, 0x40,
    0x62, 0x54, 0x01, 0x20, 0x40, 0x88, 0x65, 0x47, 0x88, 0x61, 0x71, 0x65,
    0x76, 0x23, 0x72, 0x62, 0x34, 0x86, 0x70, 0x30, 0x11, 0x51, 0x15, 0x63,
    0x20, 0x50, 0x75, 0x35, 0x02, 0x12, 0x21, 0x08, 0x42, 0x65, 0x31, 0x43,
    0x55, 0x67, 0x11, 0x15, 0x25, 0x72, 0x01, 0x06, 0x85, 0x36, 0x30, 0x15,
    0x05, 0x57, 0x58, 0x60, 0x58, 0x78, 0x43, 0x14, 0x31, 0x32, 0x78, 0x78,
    0x80, 0x87, 0x38, 0x47, 0x88, 0x63, 0x78, 0x81, 0x81, 0x38, 0x73, 0x42,
    0x61, 0x78, 0x38, 0x85, 0x24, 0x66, 0x77, 0x33, 0x50, 0x60, 0x21, 0x15,
    0x14, 0x64, 0x23, 0x82, 0x32, 0x68, 0x01, 0x35, 0x44, 0x07, 0x83, 0x47,
    0x53, 0x85, 0x53, 0x57, 0x52, 0x83, 0x23, 0x35, 0x18, 0x76, 0x01, 0x15,
    0x21, 0x34, 0x32, 0x57, 0x73, 0x33, 0x36, 0x55, 0x18, 0x86, 0x15, 0x81,
    0x61, 0x68, 0x24, 0x18, 0x42, 0x21, 0x22, 0x30, 0x84, 0x14, 0x48, 0x15,
    0x12, 0x01, 0x10, 0x30, 0x24, 0x77, 0x72, 0x42, 0x54, 0x43, 0x66, 0x06,
    0x77, 0x17, 0x70, 0x76, 0x03, 0x01, 0x45, 0x25, 0x40, 0x35, 0x00, 0x18,
    0x38, 0x73, 0x23, 0x77, 0x35, 0x26, 0x50, 0x86, 0x35, 0x71, 0x13, 0x73,
    0x44, 0x81, 0x60, 0x52, 0x77, 0x45, 0x65, 0x53, 0x73, 0x00, 0x85, 0x83,
    0x77, 0x85, 0x03, 0x51, 0x21, 0x11, 0x54, 0x80, 0x62, 0x88, 0x50, 0x18,
    0x02, 0x68, 0x13, 0x86, 0x52, 0x05, 0x34, 0x68, 0x01, 0x32, 0x07, 0x24,
    0x18, 0x03, 0x21, 0x30, 0x05, 0x72, 0x38, 0x64, 0x07, 0x64, 0x27, 0x11,
    0x41, 0x01, 0x83, 0x85, 0x25, 0x51, 0x06, 0x32, 0x60, 0x71, 0x04, 0x86,
    0x51, 0x76, 0x83, 0x38, 0x28, 0x57, 0x27, 0x62, 0x35, 0x45, 0x18, 0x73,
    0x50, 0x83, 0x13, 0x28, 0x86, 0x37, 0x66, 0x61, 0x42, 0x63, 0x11, 0x67,
    0x50, 0x33, 0x11, 0x25, 0x53, 0x76, 0x41, 0x76, 0x03, 0x14, 0x33, 0x17,
    0x72, 0x12, 0x23, 0x44, 0x18, 0xA8, 0x2E, 0x4F, 0x5C, 0x9E, 0xA0, 0xFA,
    0xF9, 0x9E, 0xB0, 0x4D, 0x78, 0xA7, 0x33, 0x27, 0x11, 0x11, 0x7C, 0x33,
    0xF1, 0x8E, 0xCA, 0x21, 0xF8, 0x74, 0x33, 0x76, 0xAD, 0xA5, 0x21, 0x98,
    0x04, 0xA7, 0xED, 0x9A, 0x55, 0x57, 0xFC, 0xD6, 0x7A, 0x35, 0x50, 0xB3,
    0xA4, 0xB8, 0xC5, 0x88, 0x62, 0x9C, 0x02, 0x14, 0x75, 0xFA, 0x3D, 0x56,
    0xD5, 0xD6, 0xCF, 0xBB, 0x1A, 0x09, 0xBD, 0xA8, 0xD1, 0x4D, 0xE6, 0x22,
    0xDD, 0xFF, 0x16, 0xD8, 0xBC, 0x99, 0xB1, 0x42, 0x78, 0xA8, 0xAF, 0x1D,
    0x76, 0xBE, 0xD1, 0x57, 0x67, 0x2D, 0xD9, 0xC3, 0x23, 0x16, 0xF9, 0x7E,
    0x8D, 0xAA, 0xDE, 0xF8, 0xD9, 0xDA, 0x69, 0x58, 0x67, 0x25, 0x56, 0x7F,
    0xB9, 0x6B, 0x59, 0x99, 0x0D, 0x4B, 0xF0, 0xBC, 0x9C, 0x19, 0x5B, 0x90,
    0xB7, 0x42, 0x95, 0xF5, 0x67, 0x5B, 0x24, 0x25, 0x7C, 0x27, 0x10, 0xC1,
    0x75, 0xB0, 0x15, 0x3F, 0x29, 0x11, 0x32, 0x8C, 0x2E, 0xB7, 0xAB, 0xB9,
    0xAD, 0x46, 0xE7, 0x0A, 0x8B, 0x53, 0xC3, 0x9E, 0xA6, 0x42, 0xCE, 0xE4,
    0xB3, 0xCB, 0x42, 0x62, 0x0E, 0x86, 0x3C, 0xE8, 0xB6, 0x50, 0xCE, 0x8A,
    0xDC, 0xD9, 0x23, 0x72, 0x1A, 0x16, 0x87, 0x02, 0x3C, 0x67, 0x3A, 0x8C,
    0xBB, 0x6B, 0x03, 0xD5, 0x1C, 0xD1, 0x97, 0xE8, 0xC3, 0x46, 0xEB, 0xAD,
    0xCE, 0x93, 0x95, 0x0F, 0x88, 0xCE, 0xE2, 0x01, 0xDB, 0x9E, 0x32, 0x08,
    0x43, 0xE2, 0x9F, 0x30, 0x0D, 0x9A, 0x19, 0x50, 0x0D, 0x70, 0xA4, 0xCA,
    0xF2, 0x72, 0xC6, 0x9E, 0x4E, 0xEF, 0x69, 0xFB, 0xB8, 0xA5, 0x5E, 0xFD,
    0x7C, 0xA2, 0xBE, 0xD9, 0x90, 0xD2, 0xD3, 0xB5, 0x82, 0x84, 0x8F, 0x9C,
    0x45, 0xC2, 0xAB, 0xC5, 0x4C, 0xFC, 0x47, 0xD3, 0x4F, 0x06, 0xC0, 0xFF,
    0xA5, 0x6F, 0xCD, 0x76, 0x2A, 0xB9, 0xCB, 0xA9, 0x14, 0x6D, 0x77, 0x25,
    0x21, 0x89, 0x63, 0xB2, 0x40, 0xD7, 0x2B, 0x6D, 0x22, 0xC9, 0x31, 0x71,
    0xFB, 0xD4, 0x77, 0x88, 0xB7, 0x6E, 0x72, 0x04, 0x2D, 0xEF, 0x08, 0x78,
    0xD2, 0x3D, 0xF6, 0x31, 0xA1, 0xA1, 0xE5, 0xA6, 0x02, 0x76, 0x86, 0xDE,
    0x5B, 0x4A, 0x10, 0xE9, 0x10, 0x69, 0xC8, 0xF2, 0xBA, 0x02, 0x59, 0xB0,
    0x4D, 0x64, 0x09, 0xDA, 0x96, 0x56, 0x7C, 0xA5, 0x2D, 0xA4, 0x97, 0x02,
    0x6E, 0x58, 0x3A, 0x0E, 0xCE, 0xFC, 0x1F, 0x01, 0xE6, 0xB9, 0x88, 0xE2,
    0x1F, 0x97, 0x67, 0xA2, 0xB7, 0xE1, 0x67, 0x2D, 0xEB, 0x9A, 0x1E, 0x2A,
    0x3F, 0xCC, 0x86, 0x3A, 0xA9, 0x15, 0x17, 0xC3, 0x34, 0x62, 0x06, 0x01,
    0xB4, 0xFE, 0x79, 0x73, 0x0E, 0x93, 0x49, 0x35, 0xF4, 0xB6, 0xFB, 0xC4,
    0xE3, 0x26, 0x95, 0x14, 0x5C, 0x2B, 0x5F, 0x6A, 0x12, 0x7F, 0xEC, 0xC0,
    0xA2, 0x77, 0x45, 0x1E, 0xBC, 0x3F, 0xD5, 0x23, 0x44, 0x4F, 0x9E, 0xE7,
    0xC9, 0xC3, 0x45, 0x34, 0xF3, 0x56, 0xDB, 0x54, 0x4F, 0xC3, 0x1C, 0x1B,
    0xFD, 0xE5, 0xF6, 0x5C, 0x77, 0xEA, 0x2F, 0x7C, 0x2E, 0xAE, 0x4C, 0x55,
    0xEB, 0xAF, 0x10, 0x42, 0x71, 0xC5, 0x66, 0xFD, 0x4E, 0xBA, 0xC7, 0x1C,
    0x7A, 0x62, 0xC7, 0x49, 0x52, 0x81, 0x7A, 0xE6, 0x75, 0x50, 0x4D, 0x95,
    0x99, 0xB1, 0xB7, 0x62, 0xB6, 0xAC, 0xA1, 0x68, 0xA8, 0x32, 0x48, 0xC9,
    0xD9, 0xAD, 0xB0, 0xCE, 0xB1, 0x55, 0x6E, 0x57, 0x59, 0x49, 0x0B, 0xBC,
    0x0C, 0x79, 0x00, 0x79, 0x5A, 0xD7, 0x21, 0x23, 0x03, 0x8B, 0x66, 0x2F,
    0x64, 0xF1, 0x06, 0xA9, 0x99, 0x36, 0x81, 0xA2, 0x5D, 0x59, 0xAF, 0x7B,
    0xC9, 0x7A, 0x23, 0x5B, 0xE9, 0x28, 0x4C, 0x5B, 0xC4, 0x5A, 0x6C, 0x90,
    0xCB, 0x1C, 0x29, 0x99, 0xC6, 0x63, 0xD9, 0x6B, 0x47, 0x8E, 0x23, 0x07,
    0xF8, 0x55, 0x48, 0x95, 0x7D, 0x65, 0x74, 0x0E, 0x26, 0x73, 0xE9, 0xEB,
    0xD1, 0x35, 0x28, 0x29, 0x03, 0x8F, 0x46, 0x2B, 0x8F, 0xD3, 0xB5, 0x68,
    0x1D, 0xA5, 0x5C, 0x02, 0x52, 0x52, 0x38, 0x53, 0x52, 0x5E, 0xA0, 0xAD,
    0x64, 0x7E, 0x71, 0xAC, 0x2C, 0x5A, 0x88, 0x93, 0xE6, 0x03, 0xAC, 0x97,
    0xE5, 0x6C, 0x04, 0xCE, 0xB2, 0xF2, 0x6F, 0x5C, 0x5B, 0x4B, 0x6D, 0x94,
    0xAB, 0x81, 0x13, 0x80, 0xFD, 0x00, 0xF2, 0x20, 0x8F, 0xE8, 0x65, 0x35,
    0x08, 0x6A, 0xEB, 0xFD, 0x35, 0xC2, 0x91, 0x20, 0x62, 0x4C, 0x04, 0xFB,
    0xB6, 0x11, 0x39, 0x29, 0xD9, 0xC5, 0x56, 0x35, 0x02, 0x53, 0x76, 0x6C,
    0x20, 0x9F, 0xDB, 0xA8, 0x3C, 0x95, 0xFC, 0xCD, 0x34, 0x2A, 0x28, 0x09,
    0x93, 0x55, 0xD0, 0x0B, 0xC8, 0x63, 0xF4, 0xEE, 0xF5, 0x96, 0xEB, 0x0B,
    0x42, 0xEB, 0xCC, 0x7C, 0x79, 0x49, 0x1C, 0xCE, 0xAE, 0x20, 0x5E, 0xA0,
    0xB8, 0x05, 0x9F, 0xBB, 0x8A, 0x57, 0x26, 0xC5, 0x94, 0x9D, 0x2B, 0x15,
    0xE7, 0xE2, 0x9C, 0x51, 0xFC, 0x9B, 0x02, 0xEE, 0x1A, 0x4F, 0xC3, 0x57,
    0xB5, 0xF1, 0xBE, 0xF9, 0xC4, 0xAD, 0xD4, 0x6A, 0x2A, 0x92, 0x0C, 0x2F,
    0xBF, 0x08, 0xA3, 0x7E, 0xB1, 0x51, 0x4B, 0xFA, 0x15, 0x11, 0x0A, 0x43,
    0x92, 0xA7, 0x4C, 0x6F, 0x13, 0xC5, 0x0C, 0x5C, 0xFF, 0xD9, 0x75, 0x31,
    0x09, 0x8D, 0x7C, 0xD2, 0x3B, 0x60, 0xEB, 0x35, 0xC4, 0xA4, 0x28, 0xB4,
    0x6C, 0x55, 0x38, 0x6E, 0x10, 0x10, 0xC4, 0xBA, 0x7F, 0x70, 0xE4, 0xC7,
    0xEC, 0xB7, 0x57, 0x5F, 0x30, 0x63, 0xA7, 0x1E, 0x84, 0xDF, 0xDC, 0xF0,
    0x9A, 0x58, 0xB2, 0xCD, 0xB0, 0xF9, 0x9F, 0x27, 0xED, 0x37, 0x86, 0x10,
    0xD2, 0x5C, 0xBA, 0xD7, 0xBF, 0xA6, 0xBA, 0x0D, 0x59, 0x18, 0x9C, 0xFE,
    0x88, 0xEA, 0xB9, 0xB4, 0x6D, 0x7E, 0x6D, 0xB0, 0x30, 0x7E, 0xAB, 0xE4,
    0x19, 0x8E, 0x99, 0xBD, 0x71, 0xF7, 0x79, 0xAB, 0x66, 0x58, 0x1E, 0x09,
    0x12, 0xFC, 0x7B, 0x1D, 0x25, 0x85, 0x24, 0x5E, 0x9A, 0x12, 0x68, 0x7A,
    0x97, 0x5C, 0xD5, 0xE8, 0xE1, 0xDC, 0xC0, 0x45, 0xD5, 0xF8, 0x91, 0xC4,
    0xC6, 0x85, 0xDB, 0x07, 0xCF, 0x81, 0xE7, 0x73, 0x89, 0xB3, 0x63, 0xEB,
    0x6B, 0xDF, 0xE3, 0x9B, 0x27, 0xFF, 0x84, 0xC9, 0x7E, 0xEF, 0xEE, 0x16,
    0x2E, 0x3B, 0x45, 0x1F, 0xE6, 0x91, 0x47, 0x19, 0xCB, 0x64, 0x36, 0xD8,
    0x55, 0x96, 0x0F, 0xF9, 0x15, 0xD7, 0xCE, 0xA6, 0xAD, 0xEA, 0xFD, 0xFC,
    0x1C, 0x05, 0x78, 0x6C, 0x49, 0xF9, 0x23, 0xA4, 0x74, 0xFF, 0xDF, 0xC3,
    0x15, 0x3A, 0x06, 0xE6, 0xED, 0x0B, 0x0A, 0xD2, 0x20, 0xD7, 0x25, 0x24,
    0x43, 0x4D, 0x52, 0x73, 0xC0, 0xAA, 0xB6, 0xDD, 0xE4, 0xE9, 0x14, 0x76,
    0xD5, 0x81, 0xA2, 0x69, 0x5A, 0x60, 0xDE, 0x6D, 0x9F, 0x44, 0xD7, 0x7A,
    0xA0, 0x82, 0x66, 0xE9, 0x38, 0xEE, 0xB4, 0xA9, 0x59, 0x7C, 0x9B, 0x64,
    0x98, 0x60, 0x59, 0xE4, 0x92, 0x62, 0xA4, 0xEA, 0xB2, 0x45, 0x4E, 0x14,
    0x01, 0x5A, 0xD0, 0x53, 0x6C, 0x42, 0x73, 0x3A, 0x5D, 0x77, 0xD7, 0x99,
    0x5C, 0x2A, 0x20, 0x44, 0x60, 0x09, 0xEB, 0xFE, 0x56, 0x32, 0xC8, 0x0C,
    0x08, 0xED, 0x2B, 0x97, 0xAF, 0x35, 0x06, 0x64, 0x89, 0xF5, 0x97, 0xEB,
    0x1B, 0x1F, 0x11, 0xF0, 0x4F, 0x60, 0xE0, 0xC9, 0x04, 0x01, 0x59, 0xC4,
    0x4A, 0xB3, 0xE6, 0x0E, 0x0A, 0x15, 0x22, 0x9D, 0x19, 0x12, 0x28, 0xBE,
    0xD1, 0x7B, 0xBC, 0x3A, 0xC9, 0x39, 0xB3, 0xC6, 0x7C, 0xEE, 0x13, 0x5F,
    0x35, 0x2C, 0x27, 0x21, 0x6C, 0x9C, 0x31, 0xF7, 0x2A, 0x3E, 0x87, 0x04,
    0x0C, 0x5F, 0x61, 0x93, 0x06, 0xEB, 0x0B, 0x6C, 0xCA, 0x2A, 0x9C, 0xE7,
    0xB2, 0x2A, 0x16, 0x94, 0xD0, 0x0C, 0xA9, 0xC0, 0x5E, 0x31, 0x51, 0x26,
    0x45, 0x7F, 0x26, 0xCE, 0x84, 0xF9, 0x61, 0x72, 0x41, 0x86, 0x07, 0x82,
    0xF8, 0x64, 0xB4, 0x73, 0xD8, 0x40, 0x17, 0x49, 0x19, 0x02, 0xB1, 0xBD,
    0xC8, 0xCD, 0xC5, 0x80, 0x0D, 0xD4, 0x61, 0x27, 0xFB, 0x80, 0xA7, 0x1C,
    0x09, 0x5B, 0x47, 0x3A, 0x56, 0x25, 0x29, 0xB3, 0xB1, 0xE7, 0xE4, 0x37,
    0xE1, 0x58, 0xA5, 0xF6, 0x66, 0x6E, 0x99, 0x74, 0xD0, 0x05, 0xB0, 0x62,
    0xC2, 0x30, 0x9E, 0x6D, 0xCE, 0x98, 0xF9, 0xB6, 0x58, 0xC6, 0xE3, 0xF9,
    0xA2, 0x16, 0xD5, 0x8C, 0x8C, 0x91, 0x42, 0xBD, 0x1C, 0x8C, 0x85, 0xA9,
    0xDA, 0x87, 0x2E, 0xBB, 0xFA, 0xD3, 0xFE, 0xA9, 0xD9, 0xAB, 0xA2, 0xB6,
    0x8C, 0x0E, 0x8F, 0x19, 0xC6, 0xFF, 0x5F, 0x00, 0x58, 0x4D, 0x45, 0xDA,
    0xF9, 0xD6, 0xC9, 0xD6, 0x9E, 0xD0, 0x4B, 0x8D, 0xA8, 0xD6, 0x87, 0x25,
    0x8B, 0x77, 0x80, 0x79, 0x27, 0x61, 0x2C, 0x53, 0x04, 0x46, 0xFE, 0xA7,
    0x69, 0x7A, 0xE3, 0xF9, 0x26, 0x69, 0x89, 0x29, 0xBC, 0x6A, 0x5A, 0x8C,
    0xF3, 0xE2, 0x02, 0x4C, 0x0F, 0x0C, 0x5E, 0xE5, 0x7B, 0x58, 0x69, 0xBF,
    0x98, 0x18, 0x81, 0xCA, 0xF9, 0xE3, 0x66, 0x5F, 0xC7, 0xF7, 0xEF, 0xC6,
    0x78, 0x92, 0x9F, 0x87, 0xA5, 0x6E, 0xAA, 0x42, 0xEA, 0x4D, 0x1F, 0xF6,
    0x69, 0x18, 0x22, 0xDD, 0x79, 0xA4, 0x70, 0x96, 0xB7, 0x76, 0xD1, 0xD8,
    0xF0, 0x14, 0x56, 0xE5, 0x87, 0x3B, 0x07, 0x38, 0x40, 0x6C, 0x38, 0x2C,
    0x57, 0x3A, 0xE9, 0xCD, 0xE2, 0xD9, 0xE7, 0xF2, 0x31, 0xB6, 0xCC, 0x5C,
    0x67, 0x6E, 0x7C, 0xF4, 0x39, 0x63, 0x37, 0x30, 0x13, 0xA5, 0x80, 0x75,
    0x38, 0x1F, 0xF0, 0x94, 0x9B, 0xE0, 0x84, 0x54, 0x6D, 0x72, 0xE4, 0xF8,
    0xA3, 0xE5, 0xFE, 0x4A, 0xA5, 0x09, 0x1A, 0xDD, 0x23, 0x4E, 0x2A, 0xFE,
    0x00, 0x30, 0xB1, 0xB6, 0x63, 0xAE, 0x9D, 0x2D, 0x32, 0x41, 0x09, 0x86,
    0xB9, 0x40, 0x2A, 0xAA, 0xF2, 0x46, 0x5B, 0x74, 0xA5, 0xE2, 0xD0, 0xBC,
    0x38, 0xE3, 0xA9, 0x2B, 0xBD, 0xDD, 0x8A, 0x1F, 0xED, 0x7B, 0x94, 0x8C,
    0x23, 0xCC, 0xE6, 0xF8, 0xC0, 0x8F, 0xE3, 0x56, 0x83, 0x5B, 0xA6, 0x5B,
    0x0F, 0x98, 0x40, 0x68, 0x61, 0x6E, 0xF4, 0x81, 0x38, 0xEF, 0xD8, 0x9B,
    0xF3, 0x57, 0xA5, 0x4D, 0x2E, 0xBB, 0xF3, 0x76, 0xCB, 0xDC, 0xC6, 0x9C,
    0x5F, 0x1F, 0x61, 0xC6, 0x4D, 0x27, 0x94, 0xBC, 0x06, 0xCC, 0xB9, 0xAB,
    0xDF, 0x66, 0xE2, 0x50, 0x85, 0xD8, 0xC8, 0x30, 0xE2, 0xAE, 0x3B, 0x0F,
    0xE0, 0xF0, 0x7A, 0x7A, 0xF8, 0xB9, 0x32, 0x0B, 0xF3, 0x42, 0x97, 0x09,
    0x97, 0xD6, 0x7D, 0x7C, 0x12, 0x59, 0x3A, 0x8F, 0xBF, 0xAD, 0xE6, 0x35,
    0xAA, 0xC5, 0x30, 0x83, 0xA7, 0x02, 0x2C, 0x47, 0xD5, 0xF7, 0x7A, 0x52,
    0xB5, 0x7B, 0x59, 0x8D, 0xA9, 0x39, 0x2A, 0xE6, 0xD8, 0x6A, 0xFC, 0x46,
    0xFC, 0x06, 0x45, 0x51, 0x81, 0xB9, 0xC7, 0x5A, 0x64, 0x6D, 0xC2, 0x1F,
    0x81, 0xE4, 0xBF, 0x21, 0x37, 0x53, 0xDE, 0x73, 0x7F, 0xD2, 0xA1, 0x40,
    0x02, 0x79, 0x20, 0xAD, 0xD3, 0x5A, 0x22, 0x3F, 0x9F, 0x5F, 0x44, 0x65,
    0xCE, 0xB6, 0x0C, 0x03, 0xED, 0x04, 0x55, 0xA3, 0x33, 0xA5, 0xCC, 0x83,
    0xAD, 0xBF, 0x43, 0xF1, 0xF4, 0x2C, 0x2C, 0xCB, 0x83, 0x28, 0xC2, 0x1C,
    0x7A, 0xB7, 0xFA, 0xED, 0x2B, 0x21, 0xCF, 0xAD, 0xE2, 0xDA, 0x55, 0x22,
    0x3A, 0xAA, 0xB2, 0xAF, 0x9B, 0x41, 0xC7, 0x33, 0x23, 0x41, 0x74, 0x63,
    0x41, 0xB3, 0x9A, 0xA2, 0xF4, 0x38, 0x15, 0x65, 0x0F, 0x54, 0x80, 0x51,
    0x14, 0x24, 0xCF, 0xA6, 0x90, 0x17, 0x79, 0xC4, 0xD1, 0x8B, 0x63, 0x8C,
    0xC0, 0x28, 0x7A, 0xAA, 0xF3, 0x16, 0x80, 0x33, 0x8D, 0x20, 0xB1, 0x7C,
    0x74, 0x49, 0xFD, 0xC6, 0xA2, 0x78, 0xA8, 0xD9, 0x6A, 0x82, 0xEE, 0x4C,
    0x4E, 0xCA, 0x40, 0x12, 0x5E, 0x2D, 0x65, 0x29, 0x00, 0x71, 0xC7, 0xAE,
    0xF1, 0xBE, 0x6A, 0x99, 0x15, 0x98, 0xFB, 0x9D, 0x59, 0x51, 0x25, 0x23,
    0xBC, 0xD4, 0xB3, 0x8C, 0x56, 0x6B, 0x8E, 0x80, 0xA7, 0x3A, 0xE3, 0x33,
    0xE1, 0x34, 0x41, 0x43, 0x27, 0xEF, 0x1D, 0x83, 0xC4, 0x7C, 0x49, 0xDF,
    0xE7, 0x93, 0x6D, 0xF1, 0x33, 0x8A, 0x5E, 0x24, 0x77, 0x87, 0x86, 0x8F,
    0xC8, 0x4F, 0xDC, 0xB9, 0x5A, 0xC8, 0x9C, 0x18, 0x5C, 0x4B, 0xB5, 0xFD,
    0x57, 0xB2, 0x33, 0x8A, 0xC4, 0x2B, 0x41, 0xC1, 0x0A, 0x82, 0x3D, 0xF3,
    0x96, 0x24, 0xF3, 0x6B, 0x15, 0xA2, 0xF0, 0x67, 0x58, 0x4E, 0x06, 0xCA,
    0x2E, 0x08, 0xCC, 0xAF, 0xF1, 0x61, 0x8F, 0xE0, 0x1D, 0xD0, 0x6D, 0xF3,
    0x51, 0x2E, 0x0B, 0x72, 0x4D, 0xEC, 0x85, 0x06, 0xDA, 0x24, 0x21, 0x5A,
    0xCA, 0xCC, 0x2C, 0x51, 0xB8, 0x2A, 0xD8, 0xD3, 0x02, 0x00, 0x2F, 0xB4,
    0x10, 0x68, 0xB1, 0xDA, 0x4F, 0x8B, 0xB1, 0x47, 0x98, 0x7B, 0x35, 0x16,
    0xBA, 0xD5, 0xDB, 0xDD, 0xF0, 0x13, 0x18, 0xFD, 0x3F, 0xA9, 0xBC, 0x43,
    0x70, 0x2A, 0xC4, 0x98, 0xC7, 0x19, 0xD9, 0x5F, 0x2E, 0x84, 0x1B, 0x62,
    0x2A, 0x5E, 0x48, 0x48, 0xA3, 0xC5, 0xC2, 0x62, 0x95, 0x99, 0x92, 0xEA,
    0x7A, 0x7D, 0x72, 0xCA, 0x8A, 0x36, 0x80, 0x28, 0xF4, 0x97, 0xDF, 0xAD,
    0x93, 0x35, 0x5C, 0xBB, 0x1B, 0xB9, 0x78, 0x6D, 0x14, 0xFF, 0x2C, 0xF5,
    0x90, 0x31, 0x78, 0x48, 0xF9, 0x58, 0x56, 0x42, 0x71, 0x10, 0xDD, 0xA3,
    0x6F, 0x51, 0x92, 0xA8, 0x16, 0xCE, 0x9C, 0x88, 0x16, 0xCC, 0x7B, 0xBF,
    0xC8, 0x04, 0xEF, 0xC4, 0x00, 0x85, 0xA3, 0x85, 0x0B, 0x89, 0xF1, 0xE7,
    0xFE, 0x56, 0x56, 0xDB, 0xA4, 0x10, 0xF9, 0x06, 0xA9, 0x7C, 0x32, 0x33,
    0x6C, 0x1A, 0xE7, 0xE8, 0x17, 0x37, 0xA8, 0x3E, 0x08, 0x73, 0x54, 0xE4,
    0x28, 0xDA, 0x85, 0x38, 0xD9, 0x48, 0xDB, 0xF5, 0xDF, 0xAC, 0xB5, 0x9D,
    0xD2, 0xB5, 0xFD, 0x3B, 0xC8, 0x03, 0xF4, 0xBA, 0x43, 0x2C, 0x9A, 0x73,
    0x9D, 0xF2, 0xCF, 0xA9, 0xED, 0x94, 0x84, 0x32, 0x0F, 0x97, 0xED, 0xFF,
    0x1A, 0x48, 0xC6, 0xB8, 0x6B, 0x30, 0x02, 0xCF, 0xB7, 0x72, 0xDD, 0x5E,
    0x56, 0x2B, 0xC4, 0xC3, 0xD6, 0x83, 0xED, 0x96, 0x4B, 0x61, 0x99, 0xFA,
    0x05, 0x14, 0xB0, 0x79, 0x0D, 0x95, 0x80, 0x95, 0xB7, 0xB8, 0x5C, 0x6B,
    0xE8, 0x75, 0xFB, 0xB5, 0x59, 0xE1, 0x93, 0x01, 0x46, 0xCC, 0xEA, 0x63,
    0xA3, 0x88, 0xA1, 0x94, 0xFE, 0x09, 0xC3, 0xDE, 0xA0, 0x3B, 0xE5, 0x2D,
    0xE2, 0x7E, 0x90, 0x10, 0x17, 0xAF, 0xE8, 0x09, 0xAF, 0x63, 0x0A, 0x73,
    0x82, 0xBF, 0x5C, 0x4C, 0xD4, 0xD1, 0xB8, 0xF4, 0x15, 0x79, 0xFB, 0x43,
    0x48, 0xED, 0xE4, 0xCA, 0x05, 0xF4, 0xCD, 0x3F, 0x13, 0x9A, 0x31, 0xB2,
    0x54, 0x4E, 0x51, 0x6D, 0xBE, 0x40, 0x86, 0xB9, 0xBB, 0x4B, 0x2B, 0xED,
    0x47, 0xE2, 0xD2, 0x30, 0x98, 0x2D, 0xD5, 0x19, 0x24, 0x29, 0xD3, 0x77,
    0xB7, 0xC0, 0x74, 0x5C, 0xC0, 0x68, 0xE2, 0xF5, 0xA4, 0xAA, 0x04, 0xC7,
    0xFF, 0x87, 0x20, 0x9E, 0xD1, 0x25, 0x99, 0x76, 0xA0, 0xFC, 0x9B, 0x25,
    0xE9, 0xE8, 0x51, 0xD4, 0xE3, 0x50, 0x2C, 0x02, 0xC8, 0x5D, 0x6D, 0xFF,
    0x02, 0x9E, 0x21, 0x1D, 0x01, 0xEB, 0xF0, 0xE9, 0xE7, 0x18, 0x8D, 0x56,
    0x8F, 0x84, 0x37, 0xD8, 0x13, 0xB0, 0xF1, 0x22, 0xF2, 0xFB, 0x17, 0x60,
    0x3B, 0x69, 0x3E, 0xD9, 0xC3, 0x8F, 0x17, 0xCF, 0xD5, 0x0B, 0x81, 0x5E,
    0x6D, 0x9D, 0xFC, 0x0E, 0xD2, 0xCC, 0xF1, 0x9F, 0x63, 0x99, 0x27, 0x4A,
    0x14, 0x20, 0xF2, 0x35, 0xA5, 0x9D, 0x8B, 0xF7, 0x24, 0x34, 0x5E, 0x14,
    0xE4, 0x5D, 0x9E, 0x4B, 0xE8, 0x93, 0x4D, 0xFC, 0x3F, 0xA9, 0x26, 0x78,
    0xDB, 0x61, 0xD7, 0x11, 0x8B, 0xF5, 0x3C, 0xB8, 0xA2, 0x22, 0x5B, 0x33,
    0x5F, 0x7E, 0xAE, 0x50, 0xE3, 0xF9, 0x41, 0x23, 0x76, 0x28, 0xDB, 0x76,
    0xD8, 0xEA, 0x38, 0xF7, 0x7A, 0x72, 0xAF, 0x3A, 0x26, 0xC8, 0x1F, 0xE4,
    0x35, 0x23, 0xB3, 0x35, 0x53, 0x5A, 0x5D, 0x1D, 0xB7, 0xC3, 0x8F, 0x34,
    0x10, 0x82, 0xBB, 0x57, 0x34, 0xD0, 0x89, 0xE8, 0xAE, 0x30, 0x9C, 0xFD,
    0xA3, 0xA0, 0xBC, 0xB5, 0xCD, 0x5B, 0x09, 0x71, 0x13, 0xC8, 0xED, 0xF9,
    0x61, 0x6A, 0xA4, 0xF6, 0xE6, 0x63, 0x1B, 0x91, 0x25, 0x27, 0x6F, 0xB3,
    0xF6, 0x80, 0xA3, 0x43, 0x41, 0xC3, 0xDB, 0x66, 0x8D, 0xC6, 0xCA, 0xD4,
    0x5F, 0xC9, 0x3B, 0x27, 0x08, 0xCA, 0x2A, 0xF7, 0x5C, 0xCC, 0xE7, 0x34,
    0xFD, 0x19, 0x1C, 0x50, 0x08, 0x9D, 0xAD, 0x53, 0x98, 0x2F, 0xDD, 0xAE,
    0x02, 0x53, 0x1F, 0xF9, 0x3E, 0x1F, 0x21, 0xFF, 0x39, 0x5F, 0xC0, 0xA1,
    0x28, 0x74, 0xED, 0xF0, 0x6B, 0x6F, 0x96, 0x47, 0xE9, 0x5A, 0x73, 0x24,
    0x58, 0x6C, 0x71, 0xDF, 0xD9, 0x1D, 0x90, 0x1D, 0x62, 0x18, 0x58, 0x19,
    0x0F, 0xEC, 0xD0, 0x0C, 0xCD, 0x11, 0x0B, 0xBA, 0xC5, 0x9F, 0x96, 0xCB,
    0x88, 0x4C, 0x3C, 0x93, 0x99, 0x47, 0x48, 0xA5, 0x6F, 0x41, 0x28, 0x3B,
    0xFC, 0x41, 0xFB, 0x89, 0x05, 0x21, 0x53, 0xA8, 0x94, 0x58, 0x8C, 0x3C,
    0xB9, 0x01, 0x7F, 0x3D, 0x66, 0x32, 0x6C, 0x98, 0x56, 0x37, 0xE5, 0x75,
    0xAC, 0xB8, 0x12, 0x34, 0x63, 0x42, 0x65, 0x40, 0x25, 0xD6, 0x02, 0xDE,
    0x3B, 0xA9, 0x40, 0xC1, 0x9A, 0xC1, 0xA6, 0x33, 0xDF, 0xFD, 0xA9, 0x77,
    0xB5, 0x29, 0xB8, 0x01, 0x3E, 0x19, 0xC1, 0xD6, 0xD0, 0x68, 0x0F, 0x4D,
    0xAE, 0x62, 0xC9, 0x24, 0x45, 0x0A, 0xE6, 0x6A, 0xAB, 0x82, 0xF2, 0x14,
    0x73, 0x06, 0x1D, 0xAB, 0x3D, 0x62, 0xB2, 0x47, 0xF9, 0x07, 0xE3, 0x55,
    0x19, 0x39, 0xAD, 0x3F, 0x54, 0x65, 0xE9, 0xD0, 0x8A, 0x82, 0xBF, 0xEA,
    0x17, 0xEE, 0xA1, 0xB6, 0xB2, 0xB9, 0x23, 0x75, 0x74, 0x77, 0xF9, 0x93,
    0x00, 0x0B, 0x2F, 0x43, 0xB7, 0x0F, 0x28, 0xAA, 0xAB, 0x1F, 0xE9, 0xA2,
    0x6A, 0xD1, 0xFD, 0x33, 0x61, 0x61, 0x6C, 0x0B, 0x0E, 0x24, 0x2F, 0xE7,
    0x66, 0x04, 0xB7, 0x03, 0x3A, 0x1F, 0x30, 0xE9, 0x7E, 0x28, 0xF5, 0x26,
    0xCA, 0x3C, 0x88, 0x0F, 0xE2, 0xB8, 0xD9, 0xD1, 0xB0, 0xC9, 0xFF, 0x18,
    0x8B, 0x31, 0xCB, 0x9D, 0x97, 0x42, 0x5A, 0xCA, 0xB9, 0xB2, 0x16, 0xD9,
    0x8A, 0x6A, 0xE3, 0x55, 0xE5, 0x83, 0xDA, 0x71, 0xE8, 0x86, 0x4E, 0xE3,
    0xD1, 0x6B, 0x07, 0x59, 0x79, 0x61, 0x90, 0xEF, 0x54, 0x5C, 0x1E, 0x62,
    0xBF, 0xEF, 0x92, 0xAF, 0x6C, 0xA1, 0x47, 0xB1, 0x32, 0x44, 0xD6, 0xC8,
    0x92, 0xFC, 0x8E, 0xF2, 0x23, 0xAB, 0x3F, 0x43, 0xF9, 0x24, 0xC2, 0xF4,
    0x66, 0x09, 0x7E, 0xE8};

static bssl::UniquePtr<EVP_PKEY> LoadExampleRSAKey() {
  bssl::UniquePtr<RSA> rsa(RSA_private_key_from_bytes(kExampleRSAKeyDER,
                                           sizeof(kExampleRSAKeyDER)));
  if (!rsa) {
    return nullptr;
  }
  bssl::UniquePtr<EVP_PKEY> pkey(EVP_PKEY_new());
  if (!pkey || !EVP_PKEY_set1_RSA(pkey.get(), rsa.get())) {
    return nullptr;
  }
  return pkey;
}

TEST(EVPExtraTest, DigestSignInit) {
  bssl::UniquePtr<EVP_PKEY> pkey = LoadExampleRSAKey();
  ASSERT_TRUE(pkey);
  bssl::ScopedEVP_MD_CTX md_ctx;
  ASSERT_TRUE(
      EVP_DigestSignInit(md_ctx.get(), NULL, EVP_sha256(), NULL, pkey.get()));
  ASSERT_TRUE(EVP_DigestSignUpdate(md_ctx.get(), kMsg, sizeof(kMsg)));

  // Determine the size of the signature.
  size_t sig_len = 0;
  ASSERT_TRUE(EVP_DigestSignFinal(md_ctx.get(), NULL, &sig_len));

  // Sanity check for testing.
  EXPECT_EQ(static_cast<size_t>(EVP_PKEY_size(pkey.get())), sig_len);

  std::vector<uint8_t> sig;
  sig.resize(sig_len);
  ASSERT_TRUE(EVP_DigestSignFinal(md_ctx.get(), sig.data(), &sig_len));
  sig.resize(sig_len);

  // Ensure that the signature round-trips.
  md_ctx.Reset();
  ASSERT_TRUE(
      EVP_DigestVerifyInit(md_ctx.get(), NULL, EVP_sha256(), NULL, pkey.get()));
  ASSERT_TRUE(EVP_DigestVerifyUpdate(md_ctx.get(), kMsg, sizeof(kMsg)));
  ASSERT_TRUE(EVP_DigestVerifyFinal(md_ctx.get(), sig.data(), sig_len));
}

TEST(EVPExtraTest, DigestVerifyInit) {
  bssl::UniquePtr<EVP_PKEY> pkey = LoadExampleRSAKey();
  bssl::ScopedEVP_MD_CTX md_ctx;
  ASSERT_TRUE(pkey);
  ASSERT_TRUE(
      EVP_DigestVerifyInit(md_ctx.get(), NULL, EVP_sha256(), NULL, pkey.get()));
  ASSERT_TRUE(EVP_DigestVerifyUpdate(md_ctx.get(), kMsg, sizeof(kMsg)));
  ASSERT_TRUE(
      EVP_DigestVerifyFinal(md_ctx.get(), kSignature, sizeof(kSignature)));
}

TEST(EVPExtraTest, VerifyRecover) {
  bssl::UniquePtr<EVP_PKEY> pkey = LoadExampleRSAKey();
  ASSERT_TRUE(pkey);
  bssl::UniquePtr<RSA> rsa(EVP_PKEY_get1_RSA(pkey.get()));
  ASSERT_TRUE(rsa);

  const uint8_t kDummyHash[32] = {0};
  uint8_t sig[2048/8];
  unsigned sig_len = sizeof(sig);
  ASSERT_TRUE(RSA_sign(NID_sha256, kDummyHash, sizeof(kDummyHash), sig,
                       &sig_len, rsa.get()));

  size_t out_len;
  bssl::UniquePtr<EVP_PKEY_CTX> ctx(EVP_PKEY_CTX_new(pkey.get(), nullptr));
  ASSERT_TRUE(EVP_PKEY_verify_recover_init(ctx.get()));
  ASSERT_TRUE(EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_PKCS1_PADDING));
  ASSERT_TRUE(EVP_PKEY_CTX_set_signature_md(ctx.get(), EVP_sha256()));
  ASSERT_TRUE(
      EVP_PKEY_verify_recover(ctx.get(), nullptr, &out_len, sig, sig_len));

  std::vector<uint8_t> recovered;
  recovered.resize(out_len);

  ASSERT_TRUE(EVP_PKEY_verify_recover(ctx.get(), recovered.data(), &out_len,
                                      sig, sig_len));
  EXPECT_EQ(Bytes(kDummyHash), Bytes(recovered.data(), out_len));

  out_len = recovered.size();
  ASSERT_TRUE(EVP_PKEY_CTX_set_signature_md(ctx.get(), nullptr));
  ASSERT_TRUE(EVP_PKEY_verify_recover(ctx.get(), recovered.data(), &out_len,
                                      sig, sig_len));

  // The size of a SHA-256 hash plus PKCS#1 v1.5 ASN.1 stuff happens to be 51
  // bytes.
  EXPECT_EQ(51u, out_len);
}

static void TestValidPrivateKey(const uint8_t *input, size_t input_len,
                                int expected_id) {
  const uint8_t *p = input;
  bssl::UniquePtr<EVP_PKEY> pkey(d2i_AutoPrivateKey(NULL, &p, input_len));
  ASSERT_TRUE(pkey);
  EXPECT_EQ(input + input_len, p);
  EXPECT_EQ(expected_id, EVP_PKEY_id(pkey.get()));
}

TEST(EVPExtraTest, d2i_AutoPrivateKey) {
  TestValidPrivateKey(kExampleRSAKeyDER, sizeof(kExampleRSAKeyDER),
                      EVP_PKEY_RSA);
  TestValidPrivateKey(kExampleRSAKeyPKCS8, sizeof(kExampleRSAKeyPKCS8),
                      EVP_PKEY_RSA);
  TestValidPrivateKey(kExampleRSAPSSKeyPKCS8, sizeof(kExampleRSAPSSKeyPKCS8),
                      EVP_PKEY_RSA_PSS);
  TestValidPrivateKey(kExampleRSAPSSKeyNoPSSParams,
                      sizeof(kExampleRSAPSSKeyNoPSSParams),
                      EVP_PKEY_RSA_PSS);
  TestValidPrivateKey(kExampleECKeyDER, sizeof(kExampleECKeyDER), EVP_PKEY_EC);
  TestValidPrivateKey(kExampleECKeyPKCS8, sizeof(kExampleECKeyPKCS8),
                      EVP_PKEY_EC);
  TestValidPrivateKey(kExampleECKeySpecifiedCurvePKCS8,
                      sizeof(kExampleECKeySpecifiedCurvePKCS8), EVP_PKEY_EC);
  TestValidPrivateKey(kExampleDSAKeyDER, sizeof(kExampleDSAKeyDER),
                      EVP_PKEY_DSA);

  const uint8_t *p = kInvalidPrivateKey;
  bssl::UniquePtr<EVP_PKEY> pkey(
      d2i_AutoPrivateKey(NULL, &p, sizeof(kInvalidPrivateKey)));
  EXPECT_FALSE(pkey) << "Parsed invalid private key";
  ERR_clear_error();
}

static bssl::UniquePtr<EVP_PKEY> ParsePrivateKey(int type, const uint8_t *in,
                                                 size_t len) {
  const uint8_t *ptr = in;
  bssl::UniquePtr<EVP_PKEY> pkey(d2i_PrivateKey(type, nullptr, &ptr, len));
  if (!pkey) {
    return nullptr;
  }

  EXPECT_EQ(in + len, ptr);
  return pkey;
}

#if !defined(__GNUC__) || (__GNUC__ > 4)

static std::string PrintToString(const EVP_PKEY *pkey, int indent,
                                 int (*print_func)(BIO *out,
                                                   const EVP_PKEY *pkey,
                                                   int indent,
                                                   ASN1_PCTX *pctx)) {
  bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
  const uint8_t *data;
  size_t len;
  if (!bio || !print_func(bio.get(), pkey, indent, nullptr) ||
      !BIO_mem_contents(bio.get(), &data, &len)) {
    ADD_FAILURE() << "Error printing.";
    return "";
  }
  return std::string(data, data + len);
}

TEST(EVPExtraTest, Print) {
  bssl::UniquePtr<EVP_PKEY> rsa = ParsePrivateKey(
      EVP_PKEY_RSA, kExampleRSAKeyDER, sizeof(kExampleRSAKeyDER));
  ASSERT_TRUE(rsa);
  EXPECT_EQ(PrintToString(rsa.get(), /*indent=*/2, &EVP_PKEY_print_params),
            "  Parameters algorithm unsupported\n");
  EXPECT_EQ(PrintToString(rsa.get(), /*indent=*/2, &EVP_PKEY_print_public),
            R"(  Public-Key: (1024 bit)
  Modulus:
      00:f8:b8:6c:83:b4:bc:d9:a8:57:c0:a5:b4:59:76:
      8c:54:1d:79:eb:22:52:04:7e:d3:37:eb:41:fd:83:
      f9:f0:a6:85:15:34:75:71:5a:84:a8:3c:d2:ef:5a:
      4e:d3:de:97:8a:dd:ff:bb:cf:0a:aa:86:92:be:b8:
      50:e4:cd:6f:80:33:30:76:13:8f:ca:7b:dc:ec:5a:
      ca:63:c7:03:25:ef:a8:8a:83:58:76:20:fa:16:77:
      d7:79:92:63:01:48:1a:d8:7b:67:f1:52:55:49:4e:
      d6:6e:4a:5c:d7:7a:37:36:0c:de:dd:8f:44:e8:c2:
      a7:2c:2b:b5:af:64:4b:61:07
  Exponent: 65537 (0x10001)
)");
  EXPECT_EQ(PrintToString(rsa.get(), /*indent=*/2, &EVP_PKEY_print_private),
            R"(  Private-Key: (1024 bit, 2 primes)
  modulus:
      00:f8:b8:6c:83:b4:bc:d9:a8:57:c0:a5:b4:59:76:
      8c:54:1d:79:eb:22:52:04:7e:d3:37:eb:41:fd:83:
      f9:f0:a6:85:15:34:75:71:5a:84:a8:3c:d2:ef:5a:
      4e:d3:de:97:8a:dd:ff:bb:cf:0a:aa:86:92:be:b8:
      50:e4:cd:6f:80:33:30:76:13:8f:ca:7b:dc:ec:5a:
      ca:63:c7:03:25:ef:a8:8a:83:58:76:20:fa:16:77:
      d7:79:92:63:01:48:1a:d8:7b:67:f1:52:55:49:4e:
      d6:6e:4a:5c:d7:7a:37:36:0c:de:dd:8f:44:e8:c2:
      a7:2c:2b:b5:af:64:4b:61:07
  publicExponent: 65537 (0x10001)
  privateExponent:
      74:88:64:3f:69:45:3a:6d:c7:7f:b9:a3:c0:6e:ec:
      dc:d4:5a:b5:32:85:5f:19:d4:f8:d4:3f:3c:fa:c2:
      f6:5f:ee:e6:ba:87:74:2e:c7:0c:d4:42:b8:66:85:
      9c:7b:24:61:aa:16:11:f6:b5:b6:a4:0a:c9:55:2e:
      81:a5:47:61:cb:25:8f:c2:15:7b:0e:7c:36:9f:3a:
      da:58:86:1c:5b:83:79:e6:2b:cc:e6:fa:2c:61:f2:
      78:80:1b:e2:f3:9d:39:2b:65:57:91:3d:71:99:73:
      a5:c2:79:20:8c:07:4f:e5:b4:60:1f:99:a2:b1:4f:
      0c:ef:bc:59:53:00:7d:b1
  prime1:
      00:fc:7e:23:65:70:f8:ce:d3:40:41:80:6a:1d:01:
      d6:01:ff:b6:1b:3d:3d:59:09:33:79:c0:4f:de:96:
      27:4b:18:c6:d9:78:f1:f4:35:46:e9:7c:42:7a:5d:
      9f:ef:54:b8:f7:9f:c4:33:6c:f3:8c:32:46:87:67:
      30:7b:a7:ac:e3
  prime2:
      00:fc:2c:df:0c:0d:88:f5:b1:92:a8:93:47:63:55:
      f5:ca:58:43:ba:1c:e5:9e:b6:95:05:cd:b5:82:df:
      eb:04:53:9d:bd:c2:38:16:b3:62:dd:a1:46:db:6d:
      97:93:9f:8a:c3:9b:64:7e:42:e3:32:57:19:1b:d5:
      6e:85:fa:b8:8d
  exponent1:
      00:bc:3d:de:6d:d6:97:e8:ba:9e:81:37:17:e5:a0:
      64:c9:00:b7:e7:fe:f4:29:d9:2e:43:6b:19:20:bd:
      99:75:e7:76:f8:d3:ae:af:7e:b8:eb:81:f4:9d:fe:
      07:2b:0b:63:0b:5a:55:90:71:7d:f1:db:d9:b1:41:
      41:68:2f:4e:39
  exponent2:
      5a:34:66:d8:f5:e2:7f:18:b5:00:6e:26:84:27:14:
      93:fb:fc:c6:0f:5e:27:e6:e1:e9:c0:8a:e4:34:da:
      e9:a2:4b:73:bc:8c:b9:ba:13:6c:7a:2b:51:84:a3:
      4a:e0:30:10:06:7e:ed:17:5a:14:00:c9:ef:85:ea:
      52:2c:bc:65
  coefficient:
      51:e3:f2:83:19:9b:c4:1e:2f:50:3d:df:5a:a2:18:
      ca:5f:2e:49:af:6f:cc:fa:65:77:94:b5:a1:0a:a9:
      d1:8a:39:37:f4:0b:a0:d7:82:27:5e:ae:17:17:a1:
      1e:54:34:bf:6e:c4:8e:99:5d:08:f1:2d:86:9d:a5:
      20:1b:e5:df
)");

  bssl::UniquePtr<EVP_PKEY> dsa = ParsePrivateKey(
      EVP_PKEY_DSA, kExampleDSAKeyDER, sizeof(kExampleDSAKeyDER));
  ASSERT_TRUE(dsa);
  EXPECT_EQ(PrintToString(dsa.get(), /*indent=*/2, &EVP_PKEY_print_params),
            R"(  DSA-Parameters: (2048 bit)
  P:
      00:9e:12:fa:b3:de:12:21:35:01:dd:82:aa:10:ca:
      2d:10:1d:2d:4e:bf:ef:4d:2a:3f:8d:aa:0f:e0:ce:
      da:d8:d6:af:85:61:6a:a2:f3:25:2c:0a:2b:5a:6d:
      b0:9e:6f:14:90:0e:0d:db:83:11:87:6d:d8:f9:66:
      95:25:f9:9e:d6:59:49:e1:84:d5:06:47:93:27:11:
      69:a2:28:68:0b:95:ec:12:f5:9a:8e:20:b2:1f:2b:
      58:eb:2a:20:12:d3:5b:de:2e:e3:51:82:2f:e8:f3:
      2d:0a:33:05:65:dc:ce:5c:67:2b:72:59:c1:4b:24:
      33:d0:b5:b2:ca:2b:2d:b0:ab:62:6e:8f:13:f4:7f:
      e0:34:5d:90:4e:72:94:bb:03:8e:9c:e2:1a:9e:58:
      0b:83:35:62:78:70:6c:fe:76:84:36:c6:9d:e1:49:
      cc:ff:98:b4:aa:b8:cb:4f:63:85:c9:f1:02:ce:59:
      34:6e:ae:ef:27:e0:ad:22:2d:53:d6:e8:9c:c8:cd:
      e5:77:6d:d0:00:57:b0:3f:2d:88:ab:3c:ed:ba:fd:
      7b:58:5f:0b:7f:78:35:e1:7a:37:28:bb:f2:5e:a6:
      25:72:f2:45:dc:11:1f:3c:e3:9c:b6:ff:ac:c3:1b:
      0a:27:90:e7:bd:e9:02:24:ea:9b:09:31:53:62:af:
      3d:2b
  Q:
      00:f3:81:dc:f5:3e:bf:72:4f:8b:2e:5c:a8:2c:01:
      0f:b4:b5:ed:a9:35:8d:0f:d8:8e:d2:78:58:94:88:
      b5:4f:c3
  G:
      0c:40:2a:72:5d:cc:3a:62:e0:2b:f4:cf:43:cd:17:
      f4:a4:93:59:12:20:22:36:69:cf:41:93:ed:ab:42:
      3a:d0:8d:fb:55:2e:30:8a:6a:57:a5:ff:bc:7c:d0:
      fb:20:87:f8:1f:8d:f0:cb:08:ab:21:33:28:7d:2b:
      69:68:71:4a:94:f6:33:c9:40:84:5a:48:a3:e1:67:
      08:dd:e7:61:cc:6a:8e:ab:2d:84:db:21:b6:ea:5b:
      07:68:14:93:cc:9c:31:fb:c3:68:b2:43:f6:dd:f8:
      c9:32:a8:b4:03:8f:44:e7:b1:5c:a8:76:34:4a:14:
      78:59:f2:b4:3b:39:45:86:68:ad:5e:0a:1a:9a:66:
      95:46:dd:28:12:e3:b3:61:7a:0a:ef:99:d5:8e:3b:
      b4:cc:87:fd:94:22:5e:01:d2:dc:c4:69:a7:72:68:
      14:6c:51:91:8f:18:e8:b4:d7:0a:a1:f0:c7:62:3b:
      cc:52:cf:37:31:d3:86:41:b2:d2:83:0b:7e:ec:b2:
      f0:95:52:ff:13:7d:04:6e:49:4e:7f:33:c3:59:00:
      02:b1:6d:1b:97:d9:36:fd:a2:8f:90:c3:ed:3c:a3:
      53:38:16:8a:c1:6f:77:c3:c5:7a:dc:2e:8f:7c:6c:
      22:56:e4:1a:5f:65:45:05:90:db:b5:bc:f0:6d:66:
      61
)");
  EXPECT_EQ(PrintToString(dsa.get(), /*indent=*/2, &EVP_PKEY_print_public),
            R"(  Public-Key: (2048 bit)
  pub:
      31:97:31:a1:4e:38:56:88:db:94:1d:bf:65:5c:da:
      4b:c2:10:de:74:20:03:ce:13:60:f2:25:1d:55:7c:
      5d:94:82:54:08:53:db:85:95:bf:dd:5e:50:d5:96:
      e0:79:51:1b:bf:4d:4e:b9:3a:c5:ee:c4:5e:98:75:
      7b:be:ff:30:e6:d0:7b:a6:f1:bc:29:ea:df:ec:f3:
      8b:fa:83:11:9f:3f:f0:5d:06:51:32:aa:21:fc:26:
      17:e7:50:c2:16:ba:fa:54:b7:7e:1d:2c:a6:a3:41:
      66:33:94:83:b9:bf:a0:4f:bd:a6:fd:2c:81:58:35:
      33:39:c0:6d:33:40:56:64:12:5a:cd:35:53:21:78:
      8f:27:24:37:66:8a:df:5e:5f:63:fc:8b:2d:ef:57:
      db:40:25:d5:17:53:0b:e4:a5:ae:54:bf:46:4f:a6:
      79:c3:74:fa:1f:85:34:64:6d:c5:03:eb:72:98:80:
      7b:c0:8f:35:11:a7:09:eb:51:e0:b0:ac:92:14:f2:
      ad:37:95:5a:ba:8c:c4:db:ed:c4:4e:8b:8f:84:33:
      64:f8:57:12:d7:08:7e:90:66:df:91:50:23:f2:73:
      c0:6b:b1:15:dd:64:d7:c9:75:17:73:72:da:33:c4:
      6f:a5:47:a1:cc:d1:c6:62:e5:ca:ab:5f:2a:8f:6b:
      cc
  P:
      00:9e:12:fa:b3:de:12:21:35:01:dd:82:aa:10:ca:
      2d:10:1d:2d:4e:bf:ef:4d:2a:3f:8d:aa:0f:e0:ce:
      da:d8:d6:af:85:61:6a:a2:f3:25:2c:0a:2b:5a:6d:
      b0:9e:6f:14:90:0e:0d:db:83:11:87:6d:d8:f9:66:
      95:25:f9:9e:d6:59:49:e1:84:d5:06:47:93:27:11:
      69:a2:28:68:0b:95:ec:12:f5:9a:8e:20:b2:1f:2b:
      58:eb:2a:20:12:d3:5b:de:2e:e3:51:82:2f:e8:f3:
      2d:0a:33:05:65:dc:ce:5c:67:2b:72:59:c1:4b:24:
      33:d0:b5:b2:ca:2b:2d:b0:ab:62:6e:8f:13:f4:7f:
      e0:34:5d:90:4e:72:94:bb:03:8e:9c:e2:1a:9e:58:
      0b:83:35:62:78:70:6c:fe:76:84:36:c6:9d:e1:49:
      cc:ff:98:b4:aa:b8:cb:4f:63:85:c9:f1:02:ce:59:
      34:6e:ae:ef:27:e0:ad:22:2d:53:d6:e8:9c:c8:cd:
      e5:77:6d:d0:00:57:b0:3f:2d:88:ab:3c:ed:ba:fd:
      7b:58:5f:0b:7f:78:35:e1:7a:37:28:bb:f2:5e:a6:
      25:72:f2:45:dc:11:1f:3c:e3:9c:b6:ff:ac:c3:1b:
      0a:27:90:e7:bd:e9:02:24:ea:9b:09:31:53:62:af:
      3d:2b
  Q:
      00:f3:81:dc:f5:3e:bf:72:4f:8b:2e:5c:a8:2c:01:
      0f:b4:b5:ed:a9:35:8d:0f:d8:8e:d2:78:58:94:88:
      b5:4f:c3
  G:
      0c:40:2a:72:5d:cc:3a:62:e0:2b:f4:cf:43:cd:17:
      f4:a4:93:59:12:20:22:36:69:cf:41:93:ed:ab:42:
      3a:d0:8d:fb:55:2e:30:8a:6a:57:a5:ff:bc:7c:d0:
      fb:20:87:f8:1f:8d:f0:cb:08:ab:21:33:28:7d:2b:
      69:68:71:4a:94:f6:33:c9:40:84:5a:48:a3:e1:67:
      08:dd:e7:61:cc:6a:8e:ab:2d:84:db:21:b6:ea:5b:
      07:68:14:93:cc:9c:31:fb:c3:68:b2:43:f6:dd:f8:
      c9:32:a8:b4:03:8f:44:e7:b1:5c:a8:76:34:4a:14:
      78:59:f2:b4:3b:39:45:86:68:ad:5e:0a:1a:9a:66:
      95:46:dd:28:12:e3:b3:61:7a:0a:ef:99:d5:8e:3b:
      b4:cc:87:fd:94:22:5e:01:d2:dc:c4:69:a7:72:68:
      14:6c:51:91:8f:18:e8:b4:d7:0a:a1:f0:c7:62:3b:
      cc:52:cf:37:31:d3:86:41:b2:d2:83:0b:7e:ec:b2:
      f0:95:52:ff:13:7d:04:6e:49:4e:7f:33:c3:59:00:
      02:b1:6d:1b:97:d9:36:fd:a2:8f:90:c3:ed:3c:a3:
      53:38:16:8a:c1:6f:77:c3:c5:7a:dc:2e:8f:7c:6c:
      22:56:e4:1a:5f:65:45:05:90:db:b5:bc:f0:6d:66:
      61
)");
  EXPECT_EQ(PrintToString(dsa.get(), /*indent=*/2, &EVP_PKEY_print_private),
            R"(  Private-Key: (2048 bit)
  priv:
      00:b0:c7:68:70:27:43:bc:51:24:29:93:a9:71:a5:
      28:89:79:54:44:f7:c6:45:22:03:d0:ce:84:fe:61:
      17:d4:6e
  pub:
      31:97:31:a1:4e:38:56:88:db:94:1d:bf:65:5c:da:
      4b:c2:10:de:74:20:03:ce:13:60:f2:25:1d:55:7c:
      5d:94:82:54:08:53:db:85:95:bf:dd:5e:50:d5:96:
      e0:79:51:1b:bf:4d:4e:b9:3a:c5:ee:c4:5e:98:75:
      7b:be:ff:30:e6:d0:7b:a6:f1:bc:29:ea:df:ec:f3:
      8b:fa:83:11:9f:3f:f0:5d:06:51:32:aa:21:fc:26:
      17:e7:50:c2:16:ba:fa:54:b7:7e:1d:2c:a6:a3:41:
      66:33:94:83:b9:bf:a0:4f:bd:a6:fd:2c:81:58:35:
      33:39:c0:6d:33:40:56:64:12:5a:cd:35:53:21:78:
      8f:27:24:37:66:8a:df:5e:5f:63:fc:8b:2d:ef:57:
      db:40:25:d5:17:53:0b:e4:a5:ae:54:bf:46:4f:a6:
      79:c3:74:fa:1f:85:34:64:6d:c5:03:eb:72:98:80:
      7b:c0:8f:35:11:a7:09:eb:51:e0:b0:ac:92:14:f2:
      ad:37:95:5a:ba:8c:c4:db:ed:c4:4e:8b:8f:84:33:
      64:f8:57:12:d7:08:7e:90:66:df:91:50:23:f2:73:
      c0:6b:b1:15:dd:64:d7:c9:75:17:73:72:da:33:c4:
      6f:a5:47:a1:cc:d1:c6:62:e5:ca:ab:5f:2a:8f:6b:
      cc
  P:
      00:9e:12:fa:b3:de:12:21:35:01:dd:82:aa:10:ca:
      2d:10:1d:2d:4e:bf:ef:4d:2a:3f:8d:aa:0f:e0:ce:
      da:d8:d6:af:85:61:6a:a2:f3:25:2c:0a:2b:5a:6d:
      b0:9e:6f:14:90:0e:0d:db:83:11:87:6d:d8:f9:66:
      95:25:f9:9e:d6:59:49:e1:84:d5:06:47:93:27:11:
      69:a2:28:68:0b:95:ec:12:f5:9a:8e:20:b2:1f:2b:
      58:eb:2a:20:12:d3:5b:de:2e:e3:51:82:2f:e8:f3:
      2d:0a:33:05:65:dc:ce:5c:67:2b:72:59:c1:4b:24:
      33:d0:b5:b2:ca:2b:2d:b0:ab:62:6e:8f:13:f4:7f:
      e0:34:5d:90:4e:72:94:bb:03:8e:9c:e2:1a:9e:58:
      0b:83:35:62:78:70:6c:fe:76:84:36:c6:9d:e1:49:
      cc:ff:98:b4:aa:b8:cb:4f:63:85:c9:f1:02:ce:59:
      34:6e:ae:ef:27:e0:ad:22:2d:53:d6:e8:9c:c8:cd:
      e5:77:6d:d0:00:57:b0:3f:2d:88:ab:3c:ed:ba:fd:
      7b:58:5f:0b:7f:78:35:e1:7a:37:28:bb:f2:5e:a6:
      25:72:f2:45:dc:11:1f:3c:e3:9c:b6:ff:ac:c3:1b:
      0a:27:90:e7:bd:e9:02:24:ea:9b:09:31:53:62:af:
      3d:2b
  Q:
      00:f3:81:dc:f5:3e:bf:72:4f:8b:2e:5c:a8:2c:01:
      0f:b4:b5:ed:a9:35:8d:0f:d8:8e:d2:78:58:94:88:
      b5:4f:c3
  G:
      0c:40:2a:72:5d:cc:3a:62:e0:2b:f4:cf:43:cd:17:
      f4:a4:93:59:12:20:22:36:69:cf:41:93:ed:ab:42:
      3a:d0:8d:fb:55:2e:30:8a:6a:57:a5:ff:bc:7c:d0:
      fb:20:87:f8:1f:8d:f0:cb:08:ab:21:33:28:7d:2b:
      69:68:71:4a:94:f6:33:c9:40:84:5a:48:a3:e1:67:
      08:dd:e7:61:cc:6a:8e:ab:2d:84:db:21:b6:ea:5b:
      07:68:14:93:cc:9c:31:fb:c3:68:b2:43:f6:dd:f8:
      c9:32:a8:b4:03:8f:44:e7:b1:5c:a8:76:34:4a:14:
      78:59:f2:b4:3b:39:45:86:68:ad:5e:0a:1a:9a:66:
      95:46:dd:28:12:e3:b3:61:7a:0a:ef:99:d5:8e:3b:
      b4:cc:87:fd:94:22:5e:01:d2:dc:c4:69:a7:72:68:
      14:6c:51:91:8f:18:e8:b4:d7:0a:a1:f0:c7:62:3b:
      cc:52:cf:37:31:d3:86:41:b2:d2:83:0b:7e:ec:b2:
      f0:95:52:ff:13:7d:04:6e:49:4e:7f:33:c3:59:00:
      02:b1:6d:1b:97:d9:36:fd:a2:8f:90:c3:ed:3c:a3:
      53:38:16:8a:c1:6f:77:c3:c5:7a:dc:2e:8f:7c:6c:
      22:56:e4:1a:5f:65:45:05:90:db:b5:bc:f0:6d:66:
      61
)");

  bssl::UniquePtr<EVP_PKEY> ec =
      ParsePrivateKey(EVP_PKEY_EC, kExampleECKeyDER, sizeof(kExampleECKeyDER));
  ASSERT_TRUE(ec);
  EXPECT_EQ(PrintToString(ec.get(), /*indent=*/2, &EVP_PKEY_print_params),
            "  ECDSA-Parameters: (P-256)\n");
  EXPECT_EQ(PrintToString(ec.get(), /*indent=*/2, &EVP_PKEY_print_public),
            R"(  Public-Key: (P-256)
  pub:
      04:e6:2b:69:e2:bf:65:9f:97:be:2f:1e:0d:94:8a:
      4c:d5:97:6b:b7:a9:1e:0d:46:fb:dd:a9:a9:1e:9d:
      dc:ba:5a:01:e7:d6:97:a8:0a:18:f9:c3:c4:a3:1e:
      56:e2:7c:83:48:db:16:1a:1c:f5:1d:7e:f1:94:2d:
      4b:cf:72:22:c1
)");
  EXPECT_EQ(PrintToString(ec.get(), /*indent=*/2, &EVP_PKEY_print_private),
            R"(  Private-Key: (P-256)
  priv:
      07:0f:08:72:7a:d4:a0:4a:9c:dd:59:c9:4d:89:68:
      77:08:b5:6f:c9:5d:30:77:0e:e8:d1:c9:ce:0a:8b:
      b4:6a
  pub:
      04:e6:2b:69:e2:bf:65:9f:97:be:2f:1e:0d:94:8a:
      4c:d5:97:6b:b7:a9:1e:0d:46:fb:dd:a9:a9:1e:9d:
      dc:ba:5a:01:e7:d6:97:a8:0a:18:f9:c3:c4:a3:1e:
      56:e2:7c:83:48:db:16:1a:1c:f5:1d:7e:f1:94:2d:
      4b:cf:72:22:c1
)");
}

#endif

// Tests loading a bad key in PKCS8 format.
TEST(EVPExtraTest, BadECKey) {
  const uint8_t *derp = kExampleBadECKeyDER;
  bssl::UniquePtr<PKCS8_PRIV_KEY_INFO> p8inf(
      d2i_PKCS8_PRIV_KEY_INFO(NULL, &derp, sizeof(kExampleBadECKeyDER)));
  ASSERT_TRUE(p8inf);
  EXPECT_EQ(kExampleBadECKeyDER + sizeof(kExampleBadECKeyDER), derp);

  bssl::UniquePtr<EVP_PKEY> pkey(EVP_PKCS82PKEY(p8inf.get()));
  ASSERT_FALSE(pkey) << "Imported invalid EC key";
  ERR_clear_error();
}

// Tests |EVP_marshal_public_key| on an empty key.
TEST(EVPExtraTest, MarshalEmptyPublicKey) {
  bssl::UniquePtr<EVP_PKEY> empty(EVP_PKEY_new());
  ASSERT_TRUE(empty);

  bssl::ScopedCBB cbb;
  EXPECT_FALSE(EVP_marshal_public_key(cbb.get(), empty.get()))
      << "Marshalled empty public key.";
  EXPECT_TRUE(ErrorEquals(ERR_peek_last_error(), ERR_LIB_EVP,
                          EVP_R_UNSUPPORTED_ALGORITHM));
}

TEST(EVPExtraTest, d2i_PrivateKey) {
  EXPECT_TRUE(ParsePrivateKey(EVP_PKEY_RSA, kExampleRSAKeyDER,
                              sizeof(kExampleRSAKeyDER)));
  EXPECT_TRUE(ParsePrivateKey(EVP_PKEY_DSA, kExampleDSAKeyDER,
                              sizeof(kExampleDSAKeyDER)));
  EXPECT_TRUE(ParsePrivateKey(EVP_PKEY_RSA, kExampleRSAKeyPKCS8,
                              sizeof(kExampleRSAKeyPKCS8)));
  EXPECT_TRUE(ParsePrivateKey(EVP_PKEY_RSA_PSS, kExampleRSAPSSKeyPKCS8,
                              sizeof(kExampleRSAPSSKeyPKCS8)));
  EXPECT_TRUE(
      ParsePrivateKey(EVP_PKEY_EC, kExampleECKeyDER, sizeof(kExampleECKeyDER)));

  EXPECT_TRUE(ParsePrivateKey(EVP_PKEY_PQDSA, kExampleMLDSA65KeyDER,
                              sizeof(kExampleMLDSA65KeyDER)));

  EXPECT_FALSE(ParsePrivateKey(EVP_PKEY_EC, kExampleBadECKeyDER,
                               sizeof(kExampleBadECKeyDER)));
  ERR_clear_error();

  // Copy the input into a |malloc|'d vector to flag memory errors.
  std::vector<uint8_t> copy(
      kExampleBadECKeyDER2,
      kExampleBadECKeyDER2 + sizeof(kExampleBadECKeyDER2));
  EXPECT_FALSE(ParsePrivateKey(EVP_PKEY_EC, copy.data(), copy.size()));
  ERR_clear_error();

  // Test that an RSA key may not be imported as an EC key.
  EXPECT_FALSE(ParsePrivateKey(EVP_PKEY_EC, kExampleRSAKeyPKCS8,
                               sizeof(kExampleRSAKeyPKCS8)));
  EXPECT_FALSE(ParsePrivateKey(EVP_PKEY_EC, kExampleRSAPSSKeyPKCS8,
                               sizeof(kExampleRSAPSSKeyPKCS8)));
  ERR_clear_error();
}

TEST(EVPExtraTest, Ed25519) {
  static const uint8_t kPublicKey[32] = {
      0xd7, 0x5a, 0x98, 0x01, 0x82, 0xb1, 0x0a, 0xb7, 0xd5, 0x4b, 0xfe,
      0xd3, 0xc9, 0x64, 0x07, 0x3a, 0x0e, 0xe1, 0x72, 0xf3, 0xda, 0xa6,
      0x23, 0x25, 0xaf, 0x02, 0x1a, 0x68, 0xf7, 0x07, 0x51, 0x1a,
  };

  static const uint8_t kPublicKeySPKI[] = {
      0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x03, 0x21,
      0x00, 0xd7, 0x5a, 0x98, 0x01, 0x82, 0xb1, 0x0a, 0xb7, 0xd5, 0x4b,
      0xfe, 0xd3, 0xc9, 0x64, 0x07, 0x3a, 0x0e, 0xe1, 0x72, 0xf3, 0xda,
      0xa6, 0x23, 0x25, 0xaf, 0x02, 0x1a, 0x68, 0xf7, 0x07, 0x51, 0x1a,
  };

  static const uint8_t kPrivateKeySeed[32] = {
      0x9d, 0x61, 0xb1, 0x9d, 0xef, 0xfd, 0x5a, 0x60, 0xba, 0x84, 0x4a,
      0xf4, 0x92, 0xec, 0x2c, 0xc4, 0x44, 0x49, 0xc5, 0x69, 0x7b, 0x32,
      0x69, 0x19, 0x70, 0x3b, 0xac, 0x03, 0x1c, 0xae, 0x7f, 0x60,
  };

  static const uint8_t kPrivateKeyPKCS8[] = {
      0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70,
      0x04, 0x22, 0x04, 0x20, 0x9d, 0x61, 0xb1, 0x9d, 0xef, 0xfd, 0x5a, 0x60,
      0xba, 0x84, 0x4a, 0xf4, 0x92, 0xec, 0x2c, 0xc4, 0x44, 0x49, 0xc5, 0x69,
      0x7b, 0x32, 0x69, 0x19, 0x70, 0x3b, 0xac, 0x03, 0x1c, 0xae, 0x7f, 0x60,
  };

  // Create a public key.
  bssl::UniquePtr<EVP_PKEY> pubkey(EVP_PKEY_new_raw_public_key(
      EVP_PKEY_ED25519, nullptr, kPublicKey, sizeof(kPublicKey)));
  ASSERT_TRUE(pubkey);
  EXPECT_EQ(EVP_PKEY_ED25519, EVP_PKEY_id(pubkey.get()));

  // The public key must be extractable.
  uint8_t buf[32];
  size_t len;
  ASSERT_TRUE(EVP_PKEY_get_raw_public_key(pubkey.get(), nullptr, &len));
  EXPECT_EQ(len, 32u);
  ASSERT_TRUE(EVP_PKEY_get_raw_public_key(pubkey.get(), buf, &len));
  EXPECT_EQ(Bytes(buf, len), Bytes(kPublicKey));
  // Passing too large of a buffer is okay. The function will still only read
  // 32 bytes.
  len = 64;
  ASSERT_TRUE(EVP_PKEY_get_raw_public_key(pubkey.get(), buf, &len));
  EXPECT_EQ(Bytes(buf, len), Bytes(kPublicKey));
  // Passing too small of a buffer is noticed.
  len = 31;
  EXPECT_FALSE(EVP_PKEY_get_raw_public_key(pubkey.get(), buf, &len));
  EXPECT_TRUE(
      ErrorEquals(ERR_get_error(), ERR_LIB_EVP, EVP_R_BUFFER_TOO_SMALL));
  ERR_clear_error();

  // There is no private key.
  EXPECT_FALSE(EVP_PKEY_get_raw_private_key(pubkey.get(), nullptr, &len));
  EXPECT_TRUE(
      ErrorEquals(ERR_get_error(), ERR_LIB_EVP, EVP_R_NOT_A_PRIVATE_KEY));
  ERR_clear_error();

  // The public key must encode properly.
  bssl::ScopedCBB cbb;
  uint8_t *der;
  size_t der_len;
  ASSERT_TRUE(CBB_init(cbb.get(), 0));
  ASSERT_TRUE(EVP_marshal_public_key(cbb.get(), pubkey.get()));
  ASSERT_TRUE(CBB_finish(cbb.get(), &der, &der_len));
  bssl::UniquePtr<uint8_t> free_der(der);
  EXPECT_EQ(Bytes(kPublicKeySPKI), Bytes(der, der_len));

  // The public key must gracefully fail to encode as a private key.
  ASSERT_TRUE(CBB_init(cbb.get(), 0));
  EXPECT_FALSE(EVP_marshal_private_key(cbb.get(), pubkey.get()));
  EXPECT_TRUE(
      ErrorEquals(ERR_get_error(), ERR_LIB_EVP, EVP_R_NOT_A_PRIVATE_KEY));
  ERR_clear_error();
  cbb.Reset();

  // Create a private key.
  bssl::UniquePtr<EVP_PKEY> privkey(EVP_PKEY_new_raw_private_key(
      EVP_PKEY_ED25519, NULL, kPrivateKeySeed, sizeof(kPrivateKeySeed)));
  ASSERT_TRUE(privkey);
  EXPECT_EQ(EVP_PKEY_ED25519, EVP_PKEY_id(privkey.get()));

  // The private key must be extractable.
  ASSERT_TRUE(EVP_PKEY_get_raw_private_key(privkey.get(), nullptr, &len));
  EXPECT_EQ(len, 32u);
  ASSERT_TRUE(EVP_PKEY_get_raw_private_key(privkey.get(), buf, &len));
  EXPECT_EQ(Bytes(buf, len), Bytes(kPrivateKeySeed));
  // Passing too large of a buffer is okay. The function will still only read
  // 32 bytes.
  len = 64;
  ASSERT_TRUE(EVP_PKEY_get_raw_private_key(privkey.get(), buf, &len));
  EXPECT_EQ(Bytes(buf, len), Bytes(kPrivateKeySeed));
  // Passing too small of a buffer is noticed.
  len = 31;
  EXPECT_FALSE(EVP_PKEY_get_raw_private_key(privkey.get(), buf, &len));
  EXPECT_TRUE(
      ErrorEquals(ERR_get_error(), ERR_LIB_EVP, EVP_R_BUFFER_TOO_SMALL));
  ERR_clear_error();
  // The public key must be extractable.
  len = 32;
  ASSERT_TRUE(EVP_PKEY_get_raw_public_key(privkey.get(), buf, &len));
  EXPECT_EQ(Bytes(buf, len), Bytes(kPublicKey));

  // The public key must encode from the private key.
  ASSERT_TRUE(CBB_init(cbb.get(), 0));
  ASSERT_TRUE(EVP_marshal_public_key(cbb.get(), privkey.get()));
  ASSERT_TRUE(CBB_finish(cbb.get(), &der, &der_len));
  free_der.reset(der);
  EXPECT_EQ(Bytes(kPublicKeySPKI), Bytes(der, der_len));

  // The private key must encode properly.
  ASSERT_TRUE(CBB_init(cbb.get(), 0));
  ASSERT_TRUE(EVP_marshal_private_key(cbb.get(), privkey.get()));
  ASSERT_TRUE(CBB_finish(cbb.get(), &der, &der_len));
  free_der.reset(der);
  EXPECT_EQ(Bytes(kPrivateKeyPKCS8), Bytes(der, der_len));

  // Test EVP_PKEY_cmp.
  EXPECT_EQ(1, EVP_PKEY_cmp(pubkey.get(), privkey.get()));

  static const uint8_t kZeros[32] = {0};
  bssl::UniquePtr<EVP_PKEY> pubkey2(EVP_PKEY_new_raw_public_key(
      EVP_PKEY_ED25519, nullptr, kZeros, sizeof(kZeros)));
  ASSERT_TRUE(pubkey2);
  EXPECT_EQ(0, EVP_PKEY_cmp(pubkey.get(), pubkey2.get()));
  EXPECT_EQ(0, EVP_PKEY_cmp(privkey.get(), pubkey2.get()));

  // Ed25519 may not be used streaming.
  bssl::ScopedEVP_MD_CTX ctx;
  ASSERT_TRUE(
      EVP_DigestSignInit(ctx.get(), nullptr, nullptr, nullptr, privkey.get()));
  EXPECT_FALSE(EVP_DigestSignUpdate(ctx.get(), nullptr, 0));
  EXPECT_FALSE(EVP_DigestSignFinal(ctx.get(), nullptr, &len));
  ERR_clear_error();

  ctx.Reset();
  ASSERT_TRUE(EVP_DigestVerifyInit(ctx.get(), nullptr, nullptr, nullptr,
                                   privkey.get()));
  EXPECT_FALSE(EVP_DigestVerifyUpdate(ctx.get(), nullptr, 0));
  EXPECT_FALSE(EVP_DigestVerifyFinal(ctx.get(), nullptr, 0));
  ERR_clear_error();

  // The buffer length to |EVP_DigestSign| is an input/output parameter and
  // should be checked before signing.
  ctx.Reset();
  ASSERT_TRUE(
      EVP_DigestSignInit(ctx.get(), nullptr, nullptr, nullptr, privkey.get()));
  len = 31;
  EXPECT_FALSE(EVP_DigestSign(ctx.get(), buf, &len, nullptr /* msg */, 0));
  EXPECT_TRUE(
      ErrorEquals(ERR_get_error(), ERR_LIB_EVP, EVP_R_BUFFER_TOO_SMALL));
  ERR_clear_error();
}

// EVP_PKEY_get_private_seed returns an error for key types that don't
// provide a get_priv_seed method. It must also reject NULL |key| regardless of
// key type.
TEST(EVPExtraTest, GetPrivateSeedUnsupportedKeyTypes) {
  // NULL key is rejected.
  size_t seed_len = 0;
  ERR_clear_error();
  EXPECT_FALSE(EVP_PKEY_get_private_seed(nullptr, nullptr, &seed_len));

  // RSA
  bssl::UniquePtr<EVP_PKEY> rsa_key(ParsePrivateKey(
      EVP_PKEY_RSA, kExampleRSAKeyDER, sizeof(kExampleRSAKeyDER)));
  ASSERT_TRUE(rsa_key);
  ERR_clear_error();
  EXPECT_FALSE(EVP_PKEY_get_private_seed(rsa_key.get(), nullptr, &seed_len));
  EXPECT_TRUE(ErrorEquals(ERR_get_error(), ERR_LIB_EVP,
                          EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE));

  // EC
  bssl::UniquePtr<EVP_PKEY> ec_key(ParsePrivateKey(
      EVP_PKEY_EC, kExampleECKeyDER, sizeof(kExampleECKeyDER)));
  ASSERT_TRUE(ec_key);
  ERR_clear_error();
  EXPECT_FALSE(EVP_PKEY_get_private_seed(ec_key.get(), nullptr, &seed_len));
  EXPECT_TRUE(ErrorEquals(ERR_get_error(), ERR_LIB_EVP,
                          EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE));

  // Ed25519: has a raw 32-byte private "seed" but does NOT wire up
  // get_priv_seed. EVP_PKEY_get_raw_private_key is the correct accessor.
  static const uint8_t kEd25519Seed[32] = {
      0x9d, 0x61, 0xb1, 0x9d, 0xef, 0xfd, 0x5a, 0x60, 0xba, 0x84, 0x4a,
      0xf4, 0x92, 0xec, 0x2c, 0xc4, 0x44, 0x49, 0xc5, 0x69, 0x7b, 0x32,
      0x69, 0x19, 0x70, 0x3b, 0xac, 0x03, 0x1c, 0xae, 0x7f, 0x60,
  };
  bssl::UniquePtr<EVP_PKEY> ed_key(EVP_PKEY_new_raw_private_key(
      EVP_PKEY_ED25519, nullptr, kEd25519Seed, sizeof(kEd25519Seed)));
  ASSERT_TRUE(ed_key);
  ERR_clear_error();
  EXPECT_FALSE(EVP_PKEY_get_private_seed(ed_key.get(), nullptr, &seed_len));
  EXPECT_TRUE(ErrorEquals(ERR_get_error(), ERR_LIB_EVP,
                          EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE));
}

static void ExpectECGroupOnly(const EVP_PKEY *pkey, int nid) {
  EC_KEY *ec = EVP_PKEY_get0_EC_KEY(pkey);
  ASSERT_TRUE(ec);
  const EC_GROUP *group = EC_KEY_get0_group(ec);
  ASSERT_TRUE(group);
  EXPECT_EQ(nid, EC_GROUP_get_curve_name(group));
  EXPECT_FALSE(EC_KEY_get0_public_key(ec));
  EXPECT_FALSE(EC_KEY_get0_private_key(ec));
}

static void ExpectECGroupAndKey(const EVP_PKEY *pkey, int nid) {
  EC_KEY *ec = EVP_PKEY_get0_EC_KEY(pkey);
  ASSERT_TRUE(ec);
  const EC_GROUP *group = EC_KEY_get0_group(ec);
  ASSERT_TRUE(group);
  EXPECT_EQ(nid, EC_GROUP_get_curve_name(group));
  EXPECT_TRUE(EC_KEY_get0_public_key(ec));
  EXPECT_TRUE(EC_KEY_get0_private_key(ec));
}

TEST(EVPExtraTest, ECKeygen) {
  for (bool copy : {false, true}) {
    SCOPED_TRACE(copy);

    auto maybe_copy = [&](bssl::UniquePtr<EVP_PKEY_CTX> *ctx) -> bool {
      if (copy) {
        ctx->reset(EVP_PKEY_CTX_dup(ctx->get()));
      }
      return *ctx != nullptr;
    };

    // |EVP_PKEY_paramgen| may be used as an extremely roundabout way to get an
    // |EC_GROUP|.
    bssl::UniquePtr<EVP_PKEY_CTX> ctx(
        EVP_PKEY_CTX_new_id(EVP_PKEY_EC, nullptr));
    ASSERT_TRUE(ctx);
    ASSERT_TRUE(maybe_copy(&ctx));
    ASSERT_TRUE(EVP_PKEY_paramgen_init(ctx.get()));
    ASSERT_TRUE(maybe_copy(&ctx));
    ASSERT_TRUE(EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx.get(),
                                                       NID_X9_62_prime256v1));
    ASSERT_TRUE(maybe_copy(&ctx));
    EVP_PKEY *raw = nullptr;
    ASSERT_TRUE(EVP_PKEY_paramgen(ctx.get(), &raw));
    // |EVP_PKEY_param_check| does not support EC keys yet.
    ASSERT_FALSE(EVP_PKEY_param_check(ctx.get()));
    bssl::UniquePtr<EVP_PKEY> pkey(raw);
    raw = nullptr;
    ExpectECGroupOnly(pkey.get(), NID_X9_62_prime256v1);

    // That resulting |EVP_PKEY| may be used as a template for key generation.
    ctx.reset(EVP_PKEY_CTX_new(pkey.get(), nullptr));
    ASSERT_TRUE(ctx);
    ASSERT_TRUE(maybe_copy(&ctx));
    ASSERT_TRUE(EVP_PKEY_keygen_init(ctx.get()));
    ASSERT_TRUE(maybe_copy(&ctx));
    raw = nullptr;
    ASSERT_TRUE(EVP_PKEY_keygen(ctx.get(), &raw));
    pkey.reset(raw);
    raw = nullptr;
    ExpectECGroupAndKey(pkey.get(), NID_X9_62_prime256v1);

    // |EVP_PKEY_paramgen| may also be skipped.
    ctx.reset(EVP_PKEY_CTX_new_id(EVP_PKEY_EC, nullptr));
    ASSERT_TRUE(ctx);
    ASSERT_TRUE(maybe_copy(&ctx));
    ASSERT_TRUE(EVP_PKEY_keygen_init(ctx.get()));
    ASSERT_TRUE(maybe_copy(&ctx));
    ASSERT_TRUE(EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx.get(),
                                                       NID_X9_62_prime256v1));
    ASSERT_TRUE(maybe_copy(&ctx));
    raw = nullptr;
    ASSERT_TRUE(EVP_PKEY_keygen(ctx.get(), &raw));
    pkey.reset(raw);
    raw = nullptr;
    ExpectECGroupAndKey(pkey.get(), NID_X9_62_prime256v1);
  }
}

TEST(EVPExtraTest, DHKeygen) {
  // Set up some DH params in an |EVP_PKEY|. There is currently no API to do
  // this from EVP directly.
  bssl::UniquePtr<BIGNUM> p(BN_get_rfc3526_prime_1536(nullptr));
  ASSERT_TRUE(p);
  bssl::UniquePtr<BIGNUM> g(BN_new());
  ASSERT_TRUE(g);
  ASSERT_TRUE(BN_set_u64(g.get(), 2));
  bssl::UniquePtr<DH> params_dh(DH_new());
  ASSERT_TRUE(params_dh);
  ASSERT_TRUE(
      DH_set0_pqg(params_dh.get(), p.release(), /*q=*/nullptr, g.release()));
  bssl::UniquePtr<EVP_PKEY> params(EVP_PKEY_new());
  ASSERT_TRUE(params);
  ASSERT_TRUE(EVP_PKEY_set1_DH(params.get(), params_dh.get()));

  for (bool copy : {false, true}) {
    SCOPED_TRACE(copy);

    auto maybe_copy = [&](bssl::UniquePtr<EVP_PKEY_CTX> *ctx) -> bool {
      if (copy) {
        ctx->reset(EVP_PKEY_CTX_dup(ctx->get()));
      }
      return *ctx != nullptr;
    };

    // |params| may be used as a template for key generation.
    bssl::UniquePtr<EVP_PKEY_CTX> ctx(EVP_PKEY_CTX_new(params.get(), nullptr));
    ASSERT_TRUE(ctx);
    ASSERT_TRUE(maybe_copy(&ctx));
    ASSERT_TRUE(EVP_PKEY_keygen_init(ctx.get()));
    ASSERT_TRUE(EVP_PKEY_param_check(ctx.get()));
    ASSERT_TRUE(maybe_copy(&ctx));
    EVP_PKEY *raw = nullptr;
    ASSERT_TRUE(EVP_PKEY_keygen(ctx.get(), &raw));
    bssl::UniquePtr<EVP_PKEY> pkey(raw);

    EXPECT_EQ(EVP_PKEY_id(pkey.get()), EVP_PKEY_DH);
    const DH *dh = EVP_PKEY_get0_DH(pkey.get());
    EXPECT_EQ(0, BN_cmp(DH_get0_p(dh), DH_get0_p(params_dh.get())));
    EXPECT_EQ(0, BN_cmp(DH_get0_g(dh), DH_get0_g(params_dh.get())));
    EXPECT_FALSE(DH_get0_q(dh));
    EXPECT_TRUE(DH_get0_pub_key(dh));
    EXPECT_TRUE(DH_get0_priv_key(dh));
    EXPECT_EQ(1, EVP_PKEY_cmp_parameters(params.get(), pkey.get()));
    EXPECT_EQ(0, EVP_PKEY_cmp(params.get(), pkey.get()));

    // Generate a second key.
    ctx.reset(EVP_PKEY_CTX_new(params.get(), nullptr));
    ASSERT_TRUE(ctx);
    ASSERT_TRUE(maybe_copy(&ctx));
    ASSERT_TRUE(EVP_PKEY_keygen_init(ctx.get()));
    ASSERT_TRUE(maybe_copy(&ctx));
    raw = nullptr;
    ASSERT_TRUE(EVP_PKEY_keygen(ctx.get(), &raw));
    bssl::UniquePtr<EVP_PKEY> pkey2(raw);

    EXPECT_EQ(1, EVP_PKEY_cmp_parameters(params.get(), pkey2.get()));
    EXPECT_EQ(1, EVP_PKEY_cmp_parameters(pkey.get(), pkey2.get()));
    EXPECT_EQ(0, EVP_PKEY_cmp(pkey.get(), pkey2.get()));
  }
}

TEST(EVPExtraTest, DHParamgen) {
  std::vector<std::pair<int, int>> test_data(
      {{768, 3}, {512, DH_GENERATOR_2}, {256, DH_GENERATOR_5}});

  for (std::pair<int, int> plgen : test_data) {
    const int prime_len = plgen.first;
    const int generator = plgen.second;
    // Construct a EVP_PKEY_CTX
    bssl::UniquePtr<EVP_PKEY_CTX> ctx(
        EVP_PKEY_CTX_new_id(EVP_PKEY_DH, nullptr));
    ASSERT_TRUE(ctx);
    // Initialize for paramgen
    ASSERT_TRUE(EVP_PKEY_paramgen_init(ctx.get()));
    // Set the prime length
    ASSERT_TRUE(EVP_PKEY_CTX_set_dh_paramgen_prime_len(ctx.get(), prime_len));
    // Set the generator
    ASSERT_TRUE(EVP_PKEY_CTX_set_dh_paramgen_generator(ctx.get(), generator));

    EVP_PKEY *raw_pkey = NULL;
    // Generate the parameters
    ASSERT_TRUE(EVP_PKEY_paramgen(ctx.get(), &raw_pkey));
    // Only parameters have been generated, but no key has actually been set.
    EXPECT_FALSE(EVP_PKEY_param_check(ctx.get()));
    bssl::UniquePtr<EVP_PKEY> pkey(raw_pkey);
    ASSERT_TRUE(raw_pkey);

    const DH* dh = EVP_PKEY_get0_DH(pkey.get());
    ASSERT_TRUE(dh);
    const BIGNUM* p = DH_get0_p(dh);
    ASSERT_TRUE(p);
    unsigned p_size = BN_num_bits(p);
    ASSERT_EQ(p_size, (unsigned)prime_len);
  }

  // Test error conditions
  const int prime_len = 255;
  const int generator = 1;
  // Construct a EVP_PKEY_CTX
  bssl::UniquePtr<EVP_PKEY_CTX> ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_DH, nullptr));
  ASSERT_TRUE(ctx);
  // Initialize for paramgen
  ASSERT_TRUE(EVP_PKEY_paramgen_init(ctx.get()));
  // Set the prime length
  ASSERT_NE(EVP_PKEY_CTX_set_dh_paramgen_prime_len(ctx.get(), prime_len), 1);
  // Set the generator
  ASSERT_NE(EVP_PKEY_CTX_set_dh_paramgen_generator(ctx.get(), generator), 1);
  ASSERT_FALSE(EVP_PKEY_param_check(ctx.get()));
}

// Test that |EVP_PKEY_keygen| works for Ed25519.
TEST(EVPExtraTest, Ed25519Keygen) {
  bssl::UniquePtr<EVP_PKEY_CTX> pctx(
      EVP_PKEY_CTX_new_id(EVP_PKEY_ED25519, nullptr));
  ASSERT_TRUE(pctx);
  ASSERT_TRUE(EVP_PKEY_keygen_init(pctx.get()));
  EVP_PKEY *raw = nullptr;
  ASSERT_TRUE(EVP_PKEY_keygen(pctx.get(), &raw));
  bssl::UniquePtr<EVP_PKEY> pkey(raw);

  // Round-trip a signature to sanity-check the key is good.
  bssl::ScopedEVP_MD_CTX ctx;
  ASSERT_TRUE(
      EVP_DigestSignInit(ctx.get(), nullptr, nullptr, nullptr, pkey.get()));
  uint8_t sig[64];
  size_t len = sizeof(sig);
  ASSERT_TRUE(EVP_DigestSign(ctx.get(), sig, &len,
                             reinterpret_cast<const uint8_t *>("hello"), 5));

  ctx.Reset();
  ASSERT_TRUE(
      EVP_DigestVerifyInit(ctx.get(), nullptr, nullptr, nullptr, pkey.get()));
  ASSERT_TRUE(EVP_DigestVerify(ctx.get(), sig, len,
                               reinterpret_cast<const uint8_t *>("hello"), 5));
}

TEST(EVPExtraTest, Ed25519i2dPrivateKey) {
  // Secret key from RFC 8032, Section 7.1, TEST 1.
  static const uint8_t kPrivateKeySeed[32] = {
      0x9d, 0x61, 0xb1, 0x9d, 0xef, 0xfd, 0x5a, 0x60, 0xba, 0x84, 0x4a,
      0xf4, 0x92, 0xec, 0x2c, 0xc4, 0x44, 0x49, 0xc5, 0x69, 0x7b, 0x32,
      0x69, 0x19, 0x70, 0x3b, 0xac, 0x03, 0x1c, 0xae, 0x7f, 0x60,
  };
  // PKCS#8 v1 encoding of the above seed, per RFC 8410, Section 7.
  static const uint8_t kPrivateKeyPKCS8[] = {
      0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70,
      0x04, 0x22, 0x04, 0x20, 0x9d, 0x61, 0xb1, 0x9d, 0xef, 0xfd, 0x5a, 0x60,
      0xba, 0x84, 0x4a, 0xf4, 0x92, 0xec, 0x2c, 0xc4, 0x44, 0x49, 0xc5, 0x69,
      0x7b, 0x32, 0x69, 0x19, 0x70, 0x3b, 0xac, 0x03, 0x1c, 0xae, 0x7f, 0x60,
  };

  bssl::UniquePtr<EVP_PKEY> pkey(EVP_PKEY_new_raw_private_key(
      EVP_PKEY_ED25519, nullptr, kPrivateKeySeed, sizeof(kPrivateKeySeed)));
  ASSERT_TRUE(pkey);

  // i2d_PrivateKey should produce PKCS#8 format for Ed25519.
  uint8_t *der_buf = nullptr;
  int der_len = i2d_PrivateKey(pkey.get(), &der_buf);
  ASSERT_GT(der_len, 0);
  bssl::UniquePtr<uint8_t> der_buf_free(der_buf);
  EXPECT_EQ(Bytes(kPrivateKeyPKCS8), Bytes(der_buf, der_len));

  // d2i_PrivateKey should parse Ed25519 PKCS#8.
  const uint8_t *inp = kPrivateKeyPKCS8;
  bssl::UniquePtr<EVP_PKEY> decoded(d2i_PrivateKey(
      EVP_PKEY_ED25519, nullptr, &inp, sizeof(kPrivateKeyPKCS8)));
  ASSERT_TRUE(decoded);
  // |inp| advanced by size of PKCS8-encoded key
  EXPECT_EQ(inp, kPrivateKeyPKCS8 + sizeof(kPrivateKeyPKCS8));
  EXPECT_EQ(EVP_PKEY_ED25519, EVP_PKEY_id(decoded.get()));

  // The decoded key must match the original.
  uint8_t original_raw[32], decoded_raw[32];
  size_t original_len = sizeof(original_raw);
  size_t decoded_len = sizeof(decoded_raw);
  ASSERT_TRUE(
      EVP_PKEY_get_raw_private_key(pkey.get(), original_raw, &original_len));
  ASSERT_TRUE(EVP_PKEY_get_raw_private_key(decoded.get(), decoded_raw,
                                            &decoded_len));
  EXPECT_EQ(Bytes(original_raw, original_len),
            Bytes(decoded_raw, decoded_len));

  // d2i_PrivateKey with the wrong type should fail.
  inp = kPrivateKeyPKCS8;
  bssl::UniquePtr<EVP_PKEY> wrong_type(
      d2i_PrivateKey(EVP_PKEY_RSA, nullptr, &inp, sizeof(kPrivateKeyPKCS8)));
  EXPECT_FALSE(wrong_type);
  ERR_clear_error();

  // d2i_AutoPrivateKey should also work with Ed25519 PKCS#8.
  inp = kPrivateKeyPKCS8;
  bssl::UniquePtr<EVP_PKEY> auto_decoded(
      d2i_AutoPrivateKey(nullptr, &inp, sizeof(kPrivateKeyPKCS8)));
  ASSERT_TRUE(auto_decoded);
  EXPECT_EQ(EVP_PKEY_ED25519, EVP_PKEY_id(auto_decoded.get()));
  decoded_len = sizeof(decoded_raw);
  ASSERT_TRUE(EVP_PKEY_get_raw_private_key(auto_decoded.get(), decoded_raw,
                                            &decoded_len));
  EXPECT_EQ(Bytes(original_raw, original_len),
            Bytes(decoded_raw, decoded_len));
}

TEST(EVPExtraTest, Ed25519i2dPublicKey) {
  // Public key from RFC 8032, Section 7.1, TEST 1.
  static const uint8_t kPublicKey[32] = {
      0xd7, 0x5a, 0x98, 0x01, 0x82, 0xb1, 0x0a, 0xb7, 0xd5, 0x4b, 0xfe,
      0xd3, 0xc9, 0x64, 0x07, 0x3a, 0x0e, 0xe1, 0x72, 0xf3, 0xda, 0xa6,
      0x23, 0x25, 0xaf, 0x02, 0x1a, 0x68, 0xf7, 0x07, 0x51, 0x1a,
  };
  // SubjectPublicKeyInfo encoding of the above key, per RFC 8410, Section 4.
  static const uint8_t kPublicKeySPKI[] = {
      0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x03, 0x21,
      0x00, 0xd7, 0x5a, 0x98, 0x01, 0x82, 0xb1, 0x0a, 0xb7, 0xd5, 0x4b,
      0xfe, 0xd3, 0xc9, 0x64, 0x07, 0x3a, 0x0e, 0xe1, 0x72, 0xf3, 0xda,
      0xa6, 0x23, 0x25, 0xaf, 0x02, 0x1a, 0x68, 0xf7, 0x07, 0x51, 0x1a,
  };

  bssl::UniquePtr<EVP_PKEY> pkey(EVP_PKEY_new_raw_public_key(
      EVP_PKEY_ED25519, nullptr, kPublicKey, sizeof(kPublicKey)));
  ASSERT_TRUE(pkey);

  // i2d_PublicKey should produce SPKI format for Ed25519.
  uint8_t *der_buf = nullptr;
  int der_len = i2d_PublicKey(pkey.get(), &der_buf);
  ASSERT_GT(der_len, 0);
  bssl::UniquePtr<uint8_t> der_buf_free(der_buf);
  EXPECT_EQ(Bytes(kPublicKeySPKI), Bytes(der_buf, der_len));

  // d2i_PublicKey should parse Ed25519 SPKI.
  const uint8_t *inp = kPublicKeySPKI;
  bssl::UniquePtr<EVP_PKEY> decoded(d2i_PublicKey(
      EVP_PKEY_ED25519, nullptr, &inp, sizeof(kPublicKeySPKI)));
  ASSERT_TRUE(decoded);
  // |inp| advanced by size of SPKI-encoded key
  EXPECT_EQ(inp, kPublicKeySPKI + sizeof(kPublicKeySPKI));
  EXPECT_EQ(EVP_PKEY_ED25519, EVP_PKEY_id(decoded.get()));

  // The decoded key must match the original.
  uint8_t original_raw[32], decoded_raw[32];
  size_t original_len = sizeof(original_raw);
  size_t decoded_len = sizeof(decoded_raw);
  ASSERT_TRUE(
      EVP_PKEY_get_raw_public_key(pkey.get(), original_raw, &original_len));
  ASSERT_TRUE(EVP_PKEY_get_raw_public_key(decoded.get(), decoded_raw,
                                           &decoded_len));
  EXPECT_EQ(Bytes(original_raw, original_len),
            Bytes(decoded_raw, decoded_len));

  // d2i_PublicKey with a mismatched non-legacy type should fail with
  // EVP_R_DIFFERENT_KEY_TYPES. Use EVP_PKEY_EC (which hits the default/SPKI
  // fallback) with Ed25519 SPKI data.
  inp = kPublicKeySPKI;
  bssl::UniquePtr<EVP_PKEY> wrong_type(
      d2i_PublicKey(EVP_PKEY_EC, nullptr, &inp, sizeof(kPublicKeySPKI)));
  EXPECT_FALSE(wrong_type);
  EXPECT_TRUE(ErrorEquals(ERR_peek_last_error(), ERR_LIB_EVP,
                          EVP_R_DIFFERENT_KEY_TYPES));
  ERR_clear_error();

  // d2i_PublicKey with invalid DER for a non-legacy type should fail with
  // EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE.
  static const uint8_t kGarbage[] = {0x00, 0x01, 0x02, 0x03};
  inp = kGarbage;
  bssl::UniquePtr<EVP_PKEY> bad_parse(
      d2i_PublicKey(EVP_PKEY_ED25519, nullptr, &inp, sizeof(kGarbage)));
  EXPECT_FALSE(bad_parse);
  EXPECT_TRUE(ErrorEquals(ERR_peek_last_error(), ERR_LIB_EVP,
                          EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE));
  ERR_clear_error();

  // i2d_PublicKey with a key that has no public encoding should fail with
  // EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE.
  bssl::UniquePtr<EVP_PKEY> empty_key(EVP_PKEY_new());
  ASSERT_TRUE(empty_key);
  EXPECT_EQ(-1, i2d_PublicKey(empty_key.get(), nullptr));
  EXPECT_TRUE(ErrorEquals(ERR_peek_last_error(), ERR_LIB_EVP,
                          EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE));
  ERR_clear_error();
}

// Test that |EVP_DigestSignFinal| and |EVP_DigestSignVerify| work with a
// a special use case of not using the one-shot |EVP_DigestSignInit| or
// |EVP_DigestVerifyInit| to initialize the |EVP_PKEY_CTX| context. The context
// data can be manually constructed using other context setting functions.
// |EVP_MD_CTX_set_pkey_ctx| was added to support this use case.
TEST(EVPExtraTest, PKEY_CTX_manual) {
  // Test the behavior with RSA Keys.
  bssl::ScopedEVP_MD_CTX ctx;
  ASSERT_TRUE(EVP_DigestInit(ctx.get(), EVP_sha256()));
  ASSERT_TRUE(EVP_DigestUpdate(ctx.get(), kMsg, sizeof(kMsg)));

  bssl::UniquePtr<EVP_PKEY> pkey = LoadExampleRSAKey();
  ASSERT_TRUE(pkey);
  bssl::UniquePtr<EVP_PKEY_CTX> pctx(EVP_PKEY_CTX_new(pkey.get(), nullptr));
  ASSERT_TRUE(pctx);

  // Manual construction for signing.
  ASSERT_TRUE(EVP_PKEY_sign_init(pctx.get()));
  ASSERT_TRUE(EVP_PKEY_CTX_set_signature_md(pctx.get(), EVP_sha256()));
  EVP_MD_CTX_set_pkey_ctx(ctx.get(), pctx.get());
  // Determine the size of the signature.
  size_t sig_len = 0;
  ASSERT_TRUE(EVP_DigestSignFinal(ctx.get(), nullptr, &sig_len));

  std::vector<uint8_t> sig;
  sig.resize(sig_len);
  ASSERT_TRUE(EVP_DigestSignFinal(ctx.get(), sig.data(), &sig_len));
  sig.resize(sig_len);

  // Manual construction for verification.
  ASSERT_TRUE(EVP_PKEY_verify_init(pctx.get()));
  ASSERT_TRUE(EVP_PKEY_CTX_set_signature_md(pctx.get(), EVP_sha256()));
  EVP_MD_CTX_set_pkey_ctx(ctx.get(), pctx.get());

  ASSERT_TRUE(EVP_DigestVerifyFinal(ctx.get(), sig.data(), sig_len));

  // Test the behavior with EC Keys.
  ctx.Reset();
  ASSERT_TRUE(EVP_DigestInit(ctx.get(), EVP_sha256()));
  ASSERT_TRUE(EVP_DigestUpdate(ctx.get(), kMsg, sizeof(kMsg)));

  // Generate generic |EC_KEY|.
  pkey.reset(EVP_PKEY_new());
  ASSERT_TRUE(pkey);
  bssl::UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
  bssl::UniquePtr<EC_KEY> eckey(EC_KEY_new());
  ASSERT_TRUE(eckey);
  ASSERT_TRUE(EC_KEY_set_group(eckey.get(), group.get()));
  EC_KEY_generate_key(eckey.get());
  ASSERT_TRUE(EVP_PKEY_set1_EC_KEY(pkey.get(), eckey.get()));
  pctx.reset(EVP_PKEY_CTX_new(pkey.get(), nullptr));

  // Manual construction for signing.
  ASSERT_TRUE(EVP_PKEY_sign_init(pctx.get()));
  ASSERT_TRUE(EVP_PKEY_CTX_set_signature_md(pctx.get(), EVP_sha256()));
  EVP_MD_CTX_set_pkey_ctx(ctx.get(), pctx.get());

  // Determine the size of the signature.
  sig_len = 0;
  ASSERT_TRUE(EVP_DigestSignFinal(ctx.get(), nullptr, &sig_len));

  sig.resize(sig_len);
  ASSERT_TRUE(EVP_DigestSignFinal(ctx.get(), sig.data(), &sig_len));
  sig.resize(sig_len);

  // Manual construction for verification.
  ASSERT_TRUE(EVP_PKEY_verify_init(pctx.get()));
  ASSERT_TRUE(EVP_PKEY_CTX_set_signature_md(pctx.get(), EVP_sha256()));
  EVP_MD_CTX_set_pkey_ctx(ctx.get(), pctx.get());

  ASSERT_TRUE(EVP_DigestVerifyFinal(ctx.get(), sig.data(), sig_len));

  // Test clean up behavior after using |EVP_MD_CTX_set_pkey_ctx|. The
  // externally set |pctx| should not be inadvertently freed.
  ASSERT_TRUE(ctx.get()->md_data);
  ASSERT_TRUE(ctx.get()->pctx);
  ASSERT_TRUE(pctx.get());
  // Clean up here.
  ASSERT_TRUE(EVP_MD_CTX_cleanup(ctx.get()));
  ASSERT_TRUE(ctx.get());
  ASSERT_FALSE(ctx.get()->md_data);
  ASSERT_FALSE(ctx.get()->pctx);
  ASSERT_TRUE(pctx.get());

  // Test assigning a NULL |pctx| with |EVP_MD_CTX_set_pkey_ctx|.
  bssl::ScopedEVP_MD_CTX md_ctx;
  bssl::UniquePtr<EVP_PKEY_CTX> null_pctx(nullptr);
  ASSERT_FALSE(null_pctx.get());
  // Assign a non-NULL pctx first.
  EVP_MD_CTX_set_pkey_ctx(md_ctx.get(), pctx.get());
  ASSERT_TRUE(md_ctx.get()->pctx);
  // Set again with NUll |pctx|.
  EVP_MD_CTX_set_pkey_ctx(md_ctx.get(), null_pctx.get());
  ASSERT_FALSE(md_ctx.get()->pctx);
  ASSERT_FALSE(null_pctx.get());
  // Check that clean up works.
  ASSERT_TRUE(EVP_MD_CTX_cleanup(md_ctx.get()));
  ASSERT_TRUE(ctx.get());
  ASSERT_FALSE(ctx.get()->md_data);
  ASSERT_FALSE(ctx.get()->pctx);
  ASSERT_TRUE(pctx.get());
}

TEST(EVPExtraTest, Parameters) {
  auto new_pkey_with_type = [](int type) -> bssl::UniquePtr<EVP_PKEY> {
    bssl::UniquePtr<EVP_PKEY> pkey(EVP_PKEY_new());
    if (!pkey ||  //
        !EVP_PKEY_set_type(pkey.get(), type)) {
      return nullptr;
    }
    return pkey;
  };

  auto new_pkey_with_curve = [](int curve_nid) -> bssl::UniquePtr<EVP_PKEY> {
    bssl::UniquePtr<EVP_PKEY_CTX> ctx(
        EVP_PKEY_CTX_new_id(EVP_PKEY_EC, nullptr));
    EVP_PKEY *pkey = nullptr;
    if (!ctx ||  //
        !EVP_PKEY_paramgen_init(ctx.get()) ||
        !EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx.get(), curve_nid) ||
        !EVP_PKEY_paramgen(ctx.get(), &pkey)) {
      return nullptr;
    }
    return bssl::UniquePtr<EVP_PKEY>(pkey);
  };

  // RSA keys have no parameters.
  bssl::UniquePtr<EVP_PKEY> rsa = new_pkey_with_type(EVP_PKEY_RSA);
  ASSERT_TRUE(rsa);
  EXPECT_FALSE(EVP_PKEY_missing_parameters(rsa.get()));

  // EC keys have parameters.
  bssl::UniquePtr<EVP_PKEY> ec_no_params = new_pkey_with_type(EVP_PKEY_EC);
  ASSERT_TRUE(ec_no_params);
  EXPECT_TRUE(EVP_PKEY_missing_parameters(ec_no_params.get()));

  bssl::UniquePtr<EVP_PKEY> p256 = new_pkey_with_curve(NID_X9_62_prime256v1);
  ASSERT_TRUE(p256);
  EXPECT_FALSE(EVP_PKEY_missing_parameters(p256.get()));

  bssl::UniquePtr<EVP_PKEY> p256_2 = new_pkey_with_curve(NID_X9_62_prime256v1);
  ASSERT_TRUE(p256_2);
  EXPECT_FALSE(EVP_PKEY_missing_parameters(p256_2.get()));

  bssl::UniquePtr<EVP_PKEY> p384 = new_pkey_with_curve(NID_secp384r1);
  ASSERT_TRUE(p384);
  EXPECT_FALSE(EVP_PKEY_missing_parameters(p384.get()));

  EXPECT_EQ(1, EVP_PKEY_cmp_parameters(p256.get(), p256_2.get()));
  EXPECT_EQ(0, EVP_PKEY_cmp_parameters(p256.get(), p384.get()));

  // Copying parameters onto a curve-less EC key works.
  ASSERT_TRUE(EVP_PKEY_copy_parameters(ec_no_params.get(), p256.get()));
  EXPECT_EQ(1, EVP_PKEY_cmp_parameters(p256.get(), ec_no_params.get()));

  // No-op copies silently succeed.
  ASSERT_TRUE(EVP_PKEY_copy_parameters(ec_no_params.get(), p256.get()));
  EXPECT_EQ(1, EVP_PKEY_cmp_parameters(p256.get(), ec_no_params.get()));

  // Copying parameters onto a type-less key works.
  bssl::UniquePtr<EVP_PKEY> pkey(EVP_PKEY_new());
  ASSERT_TRUE(pkey);
  ASSERT_TRUE(EVP_PKEY_copy_parameters(pkey.get(), p256.get()));
  EXPECT_EQ(EVP_PKEY_EC, EVP_PKEY_id(pkey.get()));
  EXPECT_EQ(1, EVP_PKEY_cmp_parameters(p256.get(), pkey.get()));

  // |EVP_PKEY_copy_parameters| cannot change a key's type or curve.
  EXPECT_FALSE(EVP_PKEY_copy_parameters(rsa.get(), p256.get()));
  EXPECT_EQ(EVP_PKEY_RSA, EVP_PKEY_id(rsa.get()));
  EXPECT_FALSE(EVP_PKEY_copy_parameters(rsa.get(), p256.get()));
  EXPECT_EQ(EVP_PKEY_RSA, EVP_PKEY_id(rsa.get()));
}

struct RsassaPssParamsMatchTestInput {
  const uint8_t *der;
  size_t der_len;
  const EVP_MD *signature_md;
  const EVP_MD *rsa_mgf1_md;
  int success;
} kRsassaPssParamsMatchTestInputs[] = {
    {kExampleRSAPSSKeyPKCS8, sizeof(kExampleRSAPSSKeyPKCS8), EVP_sha1(),
     EVP_sha1(), 0},
    {kExampleRSAPSSKeyPKCS8, sizeof(kExampleRSAPSSKeyPKCS8), EVP_sha224(),
     EVP_sha224(), 0},
    {kExampleRSAPSSKeyPKCS8, sizeof(kExampleRSAPSSKeyPKCS8), EVP_sha256(),
     EVP_sha256(), 1},
    {kExampleRSAPSSKeyPKCS8, sizeof(kExampleRSAPSSKeyPKCS8), EVP_sha384(),
     EVP_sha384(), 0},
    {kExampleRSAPSSKeyPKCS8, sizeof(kExampleRSAPSSKeyPKCS8), EVP_sha512(),
     EVP_sha512(), 0},
    {kExampleRSAPSSKeyPKCS8, sizeof(kExampleRSAPSSKeyPKCS8), EVP_sha512_224(),
     EVP_sha512_224(), 0},
    {kExampleRSAPSSKeyPKCS8, sizeof(kExampleRSAPSSKeyPKCS8), EVP_sha512_256(),
     EVP_sha512_256(), 0},
    // This test expects success when setting |signature_md| and |rsa_mgf1_md|
    // because |kExampleRSAPSSKeyNoPSSParams| has no pss restriction.
    {kExampleRSAPSSKeyNoPSSParams, sizeof(kExampleRSAPSSKeyNoPSSParams), EVP_sha256(),
     EVP_sha256(), 1},
};

class EVPRsaPssExtraTest
    : public testing::TestWithParam<RsassaPssParamsMatchTestInput> {};

// This test checks params match.
// All parameters in the signature structure algorithm identifier MUST
// match the parameters in the key structure algorithm identifier except
// the saltLength field.
// See 3.3. https://tools.ietf.org/html/rfc4055#section-3.3
TEST_P(EVPRsaPssExtraTest, PssParamsMatch) {
  const auto &param = GetParam();
  const uint8_t *p = param.der;
  const EVP_MD *signature_md = param.signature_md;
  const EVP_MD *rsa_mgf1_md = param.rsa_mgf1_md;
  // Holds ownership of heap-allocated EVP_PKEY.
  bssl::UniquePtr<EVP_PKEY> pkey_up(
      d2i_AutoPrivateKey(nullptr, &p, param.der_len));
  ASSERT_TRUE(pkey_up);
  EXPECT_EQ(param.der + param.der_len, p);
  EXPECT_EQ(EVP_PKEY_RSA_PSS, EVP_PKEY_id(pkey_up.get()));
  // Holds ownership of heap-allocated EVP_PKEY_CTX.
  bssl::UniquePtr<EVP_PKEY_CTX> pkey_ctx_up(
      EVP_PKEY_CTX_new(pkey_up.get(), nullptr));
  ASSERT_TRUE(pkey_ctx_up);
  EVP_PKEY_CTX *pkey_ctx = pkey_ctx_up.get();
  // Init pss params by calling |EVP_PKEY_sign_init|.
  // These pss params are fetched from the key structure.
  ASSERT_TRUE(EVP_PKEY_sign_init(pkey_ctx));
  EXPECT_TRUE(EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING));
  // Compare one way hash func.
  EXPECT_EQ(EVP_PKEY_CTX_set_signature_md(pkey_ctx, signature_md), param.success);
  // Compare one way hash func of mask gen.
  EXPECT_EQ(EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, rsa_mgf1_md), param.success);
  EXPECT_TRUE(
      EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, RSA_PSS_SALTLEN_DIGEST));
  ERR_clear_error();
}

INSTANTIATE_TEST_SUITE_P(All, EVPRsaPssExtraTest,
                         testing::ValuesIn(kRsassaPssParamsMatchTestInputs));

struct BadPssKeyTestInput {
  const uint8_t *der;
  size_t der_len;
} kBadPssKeyTestInputs[] = {
    {badRSAPSSKeyPKCS8_SaltLengthTooLarge, sizeof(badRSAPSSKeyPKCS8_SaltLengthTooLarge)},
};

class EVPRsaPssBadKeyTest : public testing::TestWithParam<BadPssKeyTestInput> {
};

// This test checks pss salt length.
TEST_P(EVPRsaPssBadKeyTest, InvalidSaltLength) {
  const auto &param = GetParam();
  const uint8_t *p = param.der;
  // Holds ownership of heap-allocated EVP_PKEY.
  bssl::UniquePtr<EVP_PKEY> pkey_up(
      d2i_AutoPrivateKey(nullptr, &p, param.der_len));
  ASSERT_TRUE(pkey_up);
  EXPECT_EQ(param.der + param.der_len, p);
  EXPECT_EQ(EVP_PKEY_RSA_PSS, EVP_PKEY_id(pkey_up.get()));
  // Holds ownership of heap-allocated EVP_PKEY_CTX.
  bssl::UniquePtr<EVP_PKEY_CTX> pkey_ctx_up(
      EVP_PKEY_CTX_new(pkey_up.get(), nullptr));
  ASSERT_TRUE(pkey_ctx_up);
  EVP_PKEY_CTX *pkey_ctx = pkey_ctx_up.get();
  // Init pss params by calling |EVP_PKEY_sign_init|.
  // During initialization, the salt length is validated.
  ASSERT_FALSE(EVP_PKEY_sign_init(pkey_ctx));
  ERR_clear_error();
}

INSTANTIATE_TEST_SUITE_P(All, EVPRsaPssBadKeyTest,
                         testing::ValuesIn(kBadPssKeyTestInputs));


// START KEM TESTS

struct KnownKEM {
  const char name[20];
  const int nid;
  const size_t public_key_len;
  const size_t secret_key_len;
  const size_t ciphertext_len;
  const size_t shared_secret_len;
  const size_t keygen_seed_len;
  const size_t encaps_seed_len;
  const char *kat_filename;
};

static const struct KnownKEM kKEMs[] = {
  {"MLKEM512", NID_MLKEM512, 800, 1632, 768, 32, 64, 32, "fipsmodule/ml_kem/kat/mlkem512.txt"},
  {"MLKEM768", NID_MLKEM768, 1184, 2400, 1088, 32, 64, 32, "fipsmodule/ml_kem/kat/mlkem768.txt"},
  {"MLKEM1024", NID_MLKEM1024, 1568, 3168, 1568, 32, 64, 32, "fipsmodule/ml_kem/kat/mlkem1024.txt"},
};

class PerKEMTest : public testing::TestWithParam<KnownKEM> {};

INSTANTIATE_TEST_SUITE_P(All, PerKEMTest, testing::ValuesIn(kKEMs),
                         [](const testing::TestParamInfo<KnownKEM> &params)
                             -> std::string { return params.param.name; });

TEST_P(PerKEMTest, KeyGeneration) {

  // ---- 1. Test basic key generation flow ----
  // Create context of KEM type.
  bssl::UniquePtr<EVP_PKEY_CTX> ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_KEM, nullptr));
  ASSERT_TRUE(ctx);

  // Setup the context with specific KEM parameters.
  int kem_nid = GetParam().nid;
  ASSERT_TRUE(EVP_PKEY_CTX_kem_set_params(ctx.get(), kem_nid));

  // Generate a key pair.
  EVP_PKEY *raw = nullptr;
  ASSERT_TRUE(EVP_PKEY_keygen_init(ctx.get()));
  ASSERT_TRUE(EVP_PKEY_keygen(ctx.get(), &raw));
  ASSERT_TRUE(raw);
  bssl::UniquePtr<EVP_PKEY> pkey(raw);

  // ---- 2. Test key generation with PKEY as a template ----
  ctx.reset(EVP_PKEY_CTX_new(pkey.get(), nullptr));
  ASSERT_TRUE(ctx);

  // Generate a key pair.
  raw = nullptr;
  ASSERT_TRUE(EVP_PKEY_keygen_init(ctx.get()));
  ASSERT_TRUE(EVP_PKEY_keygen(ctx.get(), &raw));
  ASSERT_TRUE(raw);
  pkey.reset(raw);

  // ---- 3. Test getting raw keys and their size ----
  size_t pk_len, sk_len;

  // First getting the sizes only.
  ASSERT_TRUE(EVP_PKEY_get_raw_public_key(pkey.get(), nullptr, &pk_len));
  ASSERT_TRUE(EVP_PKEY_get_raw_private_key(pkey.get(), nullptr, &sk_len));
  EXPECT_EQ(pk_len, GetParam().public_key_len);
  EXPECT_EQ(sk_len, GetParam().secret_key_len);

  // Then getting the keys and the sizes.
  std::vector<uint8_t> pk_raw(pk_len);
  std::vector<uint8_t> sk_raw(sk_len);
  ASSERT_TRUE(EVP_PKEY_get_raw_public_key(pkey.get(), pk_raw.data(), &pk_len));
  ASSERT_TRUE(EVP_PKEY_get_raw_private_key(pkey.get(), sk_raw.data(), &sk_len));
  EXPECT_EQ(pk_len, GetParam().public_key_len);
  EXPECT_EQ(sk_len, GetParam().secret_key_len);

  // ---- 4. Test failure modes for EVP_PKEY_CTX_kem_set_params. ----
  // ctx is NULL.
  ASSERT_FALSE(EVP_PKEY_CTX_kem_set_params(nullptr, kem_nid));
  uint32_t err = ERR_get_error();
  EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
  EXPECT_EQ(ERR_R_PASSED_NULL_PARAMETER, ERR_GET_REASON(err));

  // ctx->data is NULL
  void *tmp = ctx.get()->data;
  ctx.get()->data = nullptr;
  ASSERT_FALSE(EVP_PKEY_CTX_kem_set_params(ctx.get(), kem_nid));
  err = ERR_get_error();
  EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
  EXPECT_EQ(ERR_R_PASSED_NULL_PARAMETER, ERR_GET_REASON(err));
  ctx.get()->data = tmp;

  // ctx->pkey is not NULL.
  ASSERT_FALSE(EVP_PKEY_CTX_kem_set_params(ctx.get(), kem_nid));
  err = ERR_get_error();
  EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
  EXPECT_EQ(EVP_R_INVALID_OPERATION, ERR_GET_REASON(err));

  // kem_nid is not a KEM.
  tmp = (void*) ctx.get()->pkey;
  ctx.get()->pkey = nullptr;
  ASSERT_FALSE(EVP_PKEY_CTX_kem_set_params(ctx.get(), NID_secp521r1));
  err = ERR_get_error();
  EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
  EXPECT_EQ(EVP_R_UNSUPPORTED_ALGORITHM, ERR_GET_REASON(err));
  ctx.get()->pkey = (EVP_PKEY*) tmp;
}

// Helper function that:
//   1. creates EVP_PKEY_CTX object of KEM type,
//   2. sets the KEM parameters according to the given nid,
//   3. generates a key pair (If |seed| is set to NULL, then randomized keygen
//   is performed, if a |seed| is provided, deterministic keygen is performed)
//   4. creates EVP_PKEY object from the generated key,
//   5. creates a new context with the EVP_PKEY object and returns it.
static bssl::UniquePtr<EVP_PKEY_CTX> setup_ctx_and_generate_key(int kem_nid, const uint8_t * seed, size_t *seed_len) {

  // Create context of KEM type.
  bssl::UniquePtr<EVP_PKEY_CTX> ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_KEM, nullptr));
  EXPECT_TRUE(ctx);

  // Setup the context with specific KEM parameters.
  EXPECT_TRUE(EVP_PKEY_CTX_kem_set_params(ctx.get(), kem_nid));

  // Generate a key pair.
  EVP_PKEY *raw = nullptr;
  EXPECT_TRUE(EVP_PKEY_keygen_init(ctx.get()));
  // If a |seed| is NULL, we use EVP_PKEY_keygen, otherwise we use EVP_PKEY_keygen_deterministic
  if (seed == nullptr){
    EXPECT_TRUE(EVP_PKEY_keygen(ctx.get(), &raw));
  }
  else{
    EXPECT_TRUE(EVP_PKEY_keygen_deterministic(ctx.get(), &raw, seed, seed_len));
  }

  EXPECT_TRUE(raw);

  // Create PKEY from the generated raw key and a new context with it.
  bssl::UniquePtr<EVP_PKEY> pkey(raw);
  ctx.reset(EVP_PKEY_CTX_new(pkey.get(), nullptr));
  EXPECT_TRUE(ctx);

  return ctx;
}

TEST_P(PerKEMTest, Encapsulation) {

  // ---- 1. Setup phase: generate a context and a key ----
  bssl::UniquePtr<EVP_PKEY_CTX> ctx;
  ctx = setup_ctx_and_generate_key(GetParam().nid, nullptr, nullptr);
  ASSERT_TRUE(ctx);

  // ---- 2. Test basic encapsulation flow ----
  // Alloc ciphertext and shared secret with the expected lengths.
  size_t ct_len = GetParam().ciphertext_len;
  size_t ss_len = GetParam().shared_secret_len;
  std::vector<uint8_t> ct(ct_len);
  std::vector<uint8_t> ss(ss_len);

  // Encapsulate.
  ASSERT_TRUE(EVP_PKEY_encapsulate(ctx.get(), ct.data(), &ct_len, ss.data(), &ss_len));

  // Check the lengths set by encapsulate are as expected.
  EXPECT_EQ(ct_len, GetParam().ciphertext_len);
  EXPECT_EQ(ss_len, GetParam().shared_secret_len);

  // ---- 3. Test getting the lengths only ----
  // Reset the length variables.
  ct_len = 0;
  ss_len = 0;

  // Get the lengths and check them.
  ASSERT_TRUE(EVP_PKEY_encapsulate(ctx.get(), nullptr, &ct_len, nullptr, &ss_len));
  EXPECT_EQ(ct_len, GetParam().ciphertext_len);
  EXPECT_EQ(ss_len, GetParam().shared_secret_len);

  // When only one of |ct| or |ss| is NULL the function fails.
  ASSERT_FALSE(EVP_PKEY_encapsulate(ctx.get(), ct.data(), &ct_len, nullptr, &ss_len));
  uint32_t err = ERR_get_error();
  EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
  EXPECT_EQ(EVP_R_MISSING_PARAMETERS, ERR_GET_REASON(err));

  ASSERT_FALSE(EVP_PKEY_encapsulate(ctx.get(), nullptr, &ct_len, ss.data(), &ss_len));
  err = ERR_get_error();
  EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
  EXPECT_EQ(EVP_R_MISSING_PARAMETERS, ERR_GET_REASON(err));

  // ---- 4. Test calling encapsulate with different lengths ----
  // Set ct length to be less than expected -- should fail.
  ct_len = GetParam().ciphertext_len - 1;
  ASSERT_FALSE(EVP_PKEY_encapsulate(ctx.get(), ct.data(), &ct_len, ss.data(), &ss_len));
  err = ERR_get_error();
  EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
  EXPECT_EQ(EVP_R_BUFFER_TOO_SMALL, ERR_GET_REASON(err));

  // Set ct length to be greater than expected -- should succeed because
  // it's ok to provide buffer that's larger than needed.
  ct_len = GetParam().ciphertext_len + 1;
  ASSERT_TRUE(EVP_PKEY_encapsulate(ctx.get(), ct.data(), &ct_len, ss.data(), &ss_len));
  EXPECT_EQ(ct_len, GetParam().ciphertext_len);

  // Set ss length to be less than expected -- should fail.
  ct_len = GetParam().ciphertext_len;
  ss_len = GetParam().shared_secret_len - 1;
  ASSERT_FALSE(EVP_PKEY_encapsulate(ctx.get(), ct.data(), &ct_len, ss.data(), &ss_len));
  err = ERR_get_error();
  EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
  EXPECT_EQ(EVP_R_BUFFER_TOO_SMALL, ERR_GET_REASON(err));

  // Set ss length to be greater than expected -- should succeed because
  // it's ok to provide buffer that's larger than needed.
  ss_len = GetParam().shared_secret_len + 1;
  ASSERT_TRUE(EVP_PKEY_encapsulate(ctx.get(), ct.data(), &ct_len, ss.data(), &ss_len));
  EXPECT_EQ(ss_len, GetParam().shared_secret_len);

  // ---- 5. Test more failure modes for EVP_PKEY_encapsulate. ----
  ASSERT_FALSE(EVP_PKEY_encapsulate(nullptr, ct.data(), &ct_len, ss.data(), &ss_len));

  void *tmp = (void*) ctx.get()->pmeth;
  ctx.get()->pmeth = nullptr;
  ASSERT_FALSE(EVP_PKEY_encapsulate(ctx.get(), ct.data(), &ct_len, ss.data(), &ss_len));
  err = ERR_get_error();
  EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
  EXPECT_EQ(EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE, ERR_GET_REASON(err));
  ctx.get()->pmeth = (EVP_PKEY_METHOD*) tmp;
}

TEST_P(PerKEMTest, Decapsulation) {

  // ---- 1. Setup phase: generate context and key and encapsulate ----
  bssl::UniquePtr<EVP_PKEY_CTX> ctx;
  ctx = setup_ctx_and_generate_key(GetParam().nid, nullptr, nullptr);
  ASSERT_TRUE(ctx);

  // Alloc ciphertext and shared secret with the expected lenghts.
  size_t ct_len = GetParam().ciphertext_len;
  size_t ss_len = GetParam().shared_secret_len;
  std::vector<uint8_t> ct(ct_len);
  std::vector<uint8_t> ss(ss_len);

  // Encapsulate.
  ASSERT_TRUE(EVP_PKEY_encapsulate(ctx.get(), ct.data(), &ct_len, ss.data(), &ss_len));

  // ---- 2. Test basic decapsulation flow ----
  // Decapsulate.
  ASSERT_TRUE(EVP_PKEY_decapsulate(ctx.get(), ss.data(), &ss_len, ct.data(), ct_len));

  // Check the length set by decapsulate is as expected.
  EXPECT_EQ(ss_len, GetParam().shared_secret_len);

  // ---- 3. Test getting the length only ----
  // Reset the length variable.
  ss_len = 0;

  // Get the lengths and check them.
  ASSERT_TRUE(EVP_PKEY_decapsulate(ctx.get(), nullptr, &ss_len, ct.data(), ct_len));
  EXPECT_EQ(ss_len, GetParam().shared_secret_len);

  // ---- 4. Test calling encapsulate with different lengths ----
  // Set ss length to be less than expected -- should fail.
  ss_len = GetParam().shared_secret_len - 1;
  ASSERT_FALSE(EVP_PKEY_encapsulate(ctx.get(), ct.data(), &ct_len, ss.data(), &ss_len));
  uint32_t err = ERR_get_error();
  EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
  EXPECT_EQ(EVP_R_BUFFER_TOO_SMALL, ERR_GET_REASON(err));

  // Set ss length to be greater than expected -- should succeed because
  // it's ok to provide buffer that's larger than needed.
  ss_len = GetParam().shared_secret_len + 1;
  ASSERT_TRUE(EVP_PKEY_decapsulate(ctx.get(), nullptr, &ss_len, ct.data(), ct_len));
  EXPECT_EQ(ss_len, GetParam().shared_secret_len);

  // ---- 5. Test more failure modes for EVP_PKEY_encapsulate. ----
  ASSERT_FALSE(EVP_PKEY_decapsulate(nullptr, ss.data(), &ss_len, ct.data(), ct_len));

  void *tmp = (void*) ctx.get()->pmeth;
  ctx.get()->pmeth = nullptr;
  ASSERT_FALSE(EVP_PKEY_decapsulate(ctx.get(), ss.data(), &ss_len, ct.data(), ct_len));
  err = ERR_get_error();
  EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
  EXPECT_EQ(EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE, ERR_GET_REASON(err));
  ctx.get()->pmeth = (EVP_PKEY_METHOD*) tmp;
}

TEST_P(PerKEMTest, EndToEnd) {
  // Simulate KEM protocol:
  //   1. Alice generates a key pair,
  //   2. Alice's sends the public key to Bob,
  //   3. Bob uses Alice's public key to do encapsulate,
  //      producing a shared secret and a ciphertext,
  //   4. Bob sends the ciphertext to Alice,
  //   5. Alice uses its secret key to decapsulates Bob's ciphertext,
  //      producing a shared secret.
  //   6. Alice's and Bob's shared secrets should be the same!

  // ---- 1. Alice: generate a context and a key ----
  bssl::UniquePtr<EVP_PKEY_CTX> a_ctx;
  a_ctx = setup_ctx_and_generate_key(GetParam().nid, nullptr, nullptr);
  ASSERT_TRUE(a_ctx);
  EVP_PKEY *a_pkey = EVP_PKEY_CTX_get0_pkey(a_ctx.get());
  ASSERT_TRUE(a_pkey);

  // ---- 2. Alice/Bob: Alice -- public key --> Bob ----
  // Alice extracts the raw public key to be sent to Bob.
  size_t pk_len = GetParam().public_key_len;
  std::vector<uint8_t> a_pk(pk_len);
  ASSERT_TRUE(EVP_PKEY_get_raw_public_key(a_pkey, a_pk.data(), &pk_len));

  // Bob receives the raw key and creates a PKEY object and context.
  bssl::UniquePtr<EVP_PKEY> b_pkey(EVP_PKEY_kem_new_raw_public_key(
              GetParam().nid, a_pk.data(), pk_len));
  ASSERT_TRUE(b_pkey);
  bssl::UniquePtr<EVP_PKEY_CTX> b_ctx(EVP_PKEY_CTX_new(b_pkey.get(), nullptr));

  // ---- 3. Bob: encapsulation ----
  size_t ct_len = GetParam().ciphertext_len;
  size_t ss_len = GetParam().shared_secret_len;
  std::vector<uint8_t> b_ct(ct_len); // Ciphertext to be sent to Alice.
  std::vector<uint8_t> b_ss(ss_len); // The shared secret.
  ASSERT_TRUE(EVP_PKEY_encapsulate(b_ctx.get(), b_ct.data(), &ct_len, b_ss.data(), &ss_len));

  // ---- 4. Alice/Bob: Bob -- ciphertext --> Alice ----
  // Nothing to do here, we simply use |b_ct|.

  // ---- 5. Alice: decapsulation ----
  std::vector<uint8_t> a_ss(ss_len); // The shared secret.
  ASSERT_TRUE(EVP_PKEY_decapsulate(a_ctx.get(), a_ss.data(), &ss_len, b_ct.data(), ct_len));

  // ---- 6. Alice's and Bob's shared secrets are the same? ----
  EXPECT_EQ(Bytes(a_ss), Bytes(b_ss));
}

// Helper macros to compare std::vector with raw pointers from pkey.
#define CMP_VEC_AND_PTR(vec, ptr, len)         \
          {                                    \
            std::vector<uint8_t> tmp(len);     \
            tmp.assign(ptr, ptr+len);          \
            EXPECT_EQ(Bytes(vec), Bytes(tmp)); \
          }

#define CMP_VEC_AND_PKEY_PUBLIC(vec, pkey, len) \
          CMP_VEC_AND_PTR(vec, pkey->pkey.kem_key->public_key, len)

#define CMP_VEC_AND_PKEY_SECRET(vec, pkey, len) \
          CMP_VEC_AND_PTR(vec, pkey->pkey.kem_key->secret_key, len)

TEST_P(PerKEMTest, RawKeyOperations) {

  // ---- 1. Setup phase: generate a context and a key ----
  // Create context of KEM type.
  bssl::UniquePtr<EVP_PKEY_CTX> ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_KEM, nullptr));
  ASSERT_TRUE(ctx);

  // Setup the context with specific KEM parameters.
  ASSERT_TRUE(EVP_PKEY_CTX_kem_set_params(ctx.get(), GetParam().nid));

  // Generate a key pair.
  EVP_PKEY *raw = nullptr;
  ASSERT_TRUE(EVP_PKEY_keygen_init(ctx.get()));
  ASSERT_TRUE(EVP_PKEY_keygen(ctx.get(), &raw));
  ASSERT_TRUE(raw);

  // Create PKEY from the generated raw key and a new context with it.
  bssl::UniquePtr<EVP_PKEY> pkey(raw);
  ctx.reset(EVP_PKEY_CTX_new(pkey.get(), nullptr));
  ASSERT_TRUE(ctx);

  // ---- 2. Test getting raw keys ----
  size_t pk_len = GetParam().public_key_len;
  size_t sk_len = GetParam().secret_key_len;
  std::vector<uint8_t> pk(pk_len);
  std::vector<uint8_t> sk(sk_len);

  ASSERT_TRUE(EVP_PKEY_get_raw_public_key(pkey.get(), pk.data(), &pk_len));
  ASSERT_TRUE(EVP_PKEY_get_raw_private_key(pkey.get(), sk.data(), &sk_len));
  EXPECT_EQ(pk_len, GetParam().public_key_len);
  EXPECT_EQ(sk_len, GetParam().secret_key_len);
  CMP_VEC_AND_PKEY_PUBLIC(pk, pkey, pk_len);
  CMP_VEC_AND_PKEY_SECRET(sk, pkey, sk_len);

  // ---- 3. Test getting key size ----
  pk_len = 0;
  sk_len = 0;
  ASSERT_TRUE(EVP_PKEY_get_raw_public_key(pkey.get(), nullptr, &pk_len));
  ASSERT_TRUE(EVP_PKEY_get_raw_private_key(pkey.get(), nullptr, &sk_len));
  EXPECT_EQ(pk_len, GetParam().public_key_len);
  EXPECT_EQ(sk_len, GetParam().secret_key_len);

  // ---- 4. Test creating new keys from raw data ----
  int nid = GetParam().nid;

  bssl::UniquePtr<EVP_PKEY> pkey_pk_new(EVP_PKEY_kem_new_raw_public_key(nid, pk.data(), pk_len));
  bssl::UniquePtr<EVP_PKEY> pkey_sk_new(EVP_PKEY_kem_new_raw_secret_key(nid, sk.data(), sk_len));
  bssl::UniquePtr<EVP_PKEY> pkey_new(EVP_PKEY_kem_new_raw_key(nid, pk.data(), pk_len, sk.data(), sk_len));

  ASSERT_TRUE(pkey_pk_new);
  ASSERT_TRUE(pkey_sk_new);
  ASSERT_TRUE(pkey_new);
  ASSERT_TRUE(EVP_PKEY_kem_check_key(pkey_new.get()));

  // Not supported for anything but EC and RSA keys
  bssl::UniquePtr<EVP_PKEY_CTX> kem_key_ctx(
          EVP_PKEY_CTX_new(pkey_new.get(), NULL));
  ASSERT_TRUE(kem_key_ctx);
  EXPECT_FALSE(EVP_PKEY_check(kem_key_ctx.get()));
  EXPECT_FALSE(EVP_PKEY_public_check((kem_key_ctx.get())));
  ASSERT_EQ((uint16_t)ERR_get_error(),
            (uint16_t)EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
  ERR_clear_error();

  // ---- 5. Test encaps/decaps with new keys ----
  // Create Alice's context with the new key that has both
  // the public and the secret part of the key.
  bssl::UniquePtr<EVP_PKEY_CTX> a_ctx(EVP_PKEY_CTX_new(pkey_new.get(), nullptr));
  ASSERT_TRUE(a_ctx);

  // Create Bob's context with the new key that has only the public part.
  bssl::UniquePtr<EVP_PKEY_CTX> b_ctx(EVP_PKEY_CTX_new(pkey_pk_new.get(), nullptr));
  ASSERT_TRUE(b_ctx);

  // Alloc memory for Bob's ciphertext and shared secret.
  size_t ct_len = GetParam().ciphertext_len;
  size_t ss_len = GetParam().shared_secret_len;
  std::vector<uint8_t> b_ct(ct_len); // Ciphertext to be sent to Alice.
  std::vector<uint8_t> b_ss(ss_len); // The shared secret.

  // Bob encapsulates.
  ASSERT_TRUE(EVP_PKEY_encapsulate(b_ctx.get(), b_ct.data(), &ct_len, b_ss.data(), &ss_len));

  // Alice decapsulates.
  std::vector<uint8_t> a_ss(ss_len); // The shared secret.
  ASSERT_TRUE(EVP_PKEY_decapsulate(a_ctx.get(), a_ss.data(), &ss_len, b_ct.data(), ct_len));

  // Alice's and Bob's shared secrets are the same?
  EXPECT_EQ(Bytes(a_ss), Bytes(b_ss));

  // ---- 6. Test failure modes ----
  // Failures for get_raw_public/private_key.
  pk_len = GetParam().public_key_len;
  sk_len = GetParam().secret_key_len;

  //   Invalid PKEY.
  ASSERT_FALSE(EVP_PKEY_get_raw_public_key(nullptr, pk.data(), &pk_len));
  uint32_t err = ERR_get_error();
  EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
  EXPECT_EQ(EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE, ERR_GET_REASON(err));

  ASSERT_FALSE(EVP_PKEY_get_raw_private_key(nullptr, sk.data(), &sk_len));
  err = ERR_get_error();
  EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
  EXPECT_EQ(EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE, ERR_GET_REASON(err));

  void *tmp = (void*) pkey.get()->ameth;
  pkey.get()->ameth = nullptr;
  ASSERT_FALSE(EVP_PKEY_get_raw_public_key(pkey.get(), pk.data(), &pk_len));
  err = ERR_get_error();
  EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
  EXPECT_EQ(EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE, ERR_GET_REASON(err));
  ASSERT_FALSE(EVP_PKEY_get_raw_private_key(pkey.get(), sk.data(), &sk_len));
  err = ERR_get_error();
  EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
  EXPECT_EQ(EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE, ERR_GET_REASON(err));
  pkey.get()->ameth = (const EVP_PKEY_ASN1_METHOD*)(tmp);

  //   Invalid lengths.
  pk_len = GetParam().public_key_len - 1;
  ASSERT_FALSE(EVP_PKEY_get_raw_public_key(pkey.get(), pk.data(), &pk_len));
  err = ERR_get_error();
  EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
  EXPECT_EQ(EVP_R_BUFFER_TOO_SMALL, ERR_GET_REASON(err));

  sk_len = GetParam().secret_key_len - 1;
  ASSERT_FALSE(EVP_PKEY_get_raw_private_key(pkey.get(), sk.data(), &sk_len));
  err = ERR_get_error();
  EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
  EXPECT_EQ(EVP_R_BUFFER_TOO_SMALL, ERR_GET_REASON(err));

  //   Missing public/private key.
  pk_len = GetParam().public_key_len;
  sk_len = GetParam().secret_key_len;
  pkey_pk_new.reset(EVP_PKEY_kem_new_raw_public_key(nid, pk.data(), pk_len));
  pkey_sk_new.reset(EVP_PKEY_kem_new_raw_secret_key(nid, sk.data(), sk_len));
  ASSERT_TRUE(pkey_pk_new);
  ASSERT_TRUE(pkey_sk_new);

  ASSERT_FALSE(EVP_PKEY_get_raw_private_key(pkey_pk_new.get(), sk.data(), &sk_len));
  err = ERR_get_error();
  EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
  EXPECT_EQ(EVP_R_NO_KEY_SET, ERR_GET_REASON(err));

  ASSERT_FALSE(EVP_PKEY_get_raw_public_key(pkey_sk_new.get(), pk.data(), &pk_len));
  err = ERR_get_error();
  EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
  EXPECT_EQ(EVP_R_NO_KEY_SET, ERR_GET_REASON(err));

  // Failures for new keys from raw data.
  pk_len = GetParam().public_key_len;
  sk_len = GetParam().secret_key_len;

  //   Invalid nid.
  ASSERT_FALSE(EVP_PKEY_kem_new_raw_public_key(0, pk.data(), pk_len));
  err = ERR_get_error();
  EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
  EXPECT_EQ(EVP_R_UNSUPPORTED_ALGORITHM, ERR_GET_REASON(err));

  ASSERT_FALSE(EVP_PKEY_kem_new_raw_secret_key(0, pk.data(), pk_len));
  err = ERR_get_error();
  EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
  EXPECT_EQ(EVP_R_UNSUPPORTED_ALGORITHM, ERR_GET_REASON(err));

  ASSERT_FALSE(EVP_PKEY_kem_new_raw_key(0, pk.data(), pk_len, sk.data(), sk_len));
  err = ERR_get_error();
  EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
  EXPECT_EQ(EVP_R_UNSUPPORTED_ALGORITHM, ERR_GET_REASON(err));

  //   Invalid input buffer.
  ASSERT_FALSE(EVP_PKEY_kem_new_raw_public_key(nid, nullptr, pk_len));
  err = ERR_get_error();
  EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
  EXPECT_EQ(ERR_R_PASSED_NULL_PARAMETER, ERR_GET_REASON(err));

  ASSERT_FALSE(EVP_PKEY_kem_new_raw_secret_key(nid, nullptr, sk_len));
  err = ERR_get_error();
  EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
  EXPECT_EQ(ERR_R_PASSED_NULL_PARAMETER, ERR_GET_REASON(err));

  ASSERT_FALSE(EVP_PKEY_kem_new_raw_key(nid, nullptr, pk_len, sk.data(), sk_len));
  err = ERR_get_error();
  EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
  EXPECT_EQ(ERR_R_PASSED_NULL_PARAMETER, ERR_GET_REASON(err));

  ASSERT_FALSE(EVP_PKEY_kem_new_raw_key(nid, pk.data(), pk_len, nullptr, sk_len));
  err = ERR_get_error();
  EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
  EXPECT_EQ(ERR_R_PASSED_NULL_PARAMETER, ERR_GET_REASON(err));

  //   Invalid lengths.
  pk_len = GetParam().public_key_len - 1;
  ASSERT_FALSE(EVP_PKEY_kem_new_raw_public_key(nid, pk.data(), pk_len));
  err = ERR_get_error();
  EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
  EXPECT_EQ(EVP_R_INVALID_BUFFER_SIZE, ERR_GET_REASON(err));

  pk_len = GetParam().public_key_len + 1;
  ASSERT_FALSE(EVP_PKEY_kem_new_raw_public_key(nid, pk.data(), pk_len));
  err = ERR_get_error();
  EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
  EXPECT_EQ(EVP_R_INVALID_BUFFER_SIZE, ERR_GET_REASON(err));

  sk_len = GetParam().secret_key_len - 1;
  ASSERT_FALSE(EVP_PKEY_kem_new_raw_secret_key(nid, sk.data(), sk_len));
  err = ERR_get_error();
  EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
  EXPECT_EQ(EVP_R_INVALID_BUFFER_SIZE, ERR_GET_REASON(err));

  sk_len = GetParam().secret_key_len + 1;
  ASSERT_FALSE(EVP_PKEY_kem_new_raw_secret_key(nid, sk.data(), sk_len));
  err = ERR_get_error();
  EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
  EXPECT_EQ(EVP_R_INVALID_BUFFER_SIZE, ERR_GET_REASON(err));

  pk_len = GetParam().public_key_len;
  sk_len = GetParam().secret_key_len - 1;
  ASSERT_FALSE(EVP_PKEY_kem_new_raw_key(nid, pk.data(), pk_len, sk.data(), sk_len));
  err = ERR_get_error();
  EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
  EXPECT_EQ(EVP_R_INVALID_BUFFER_SIZE, ERR_GET_REASON(err));

  pk_len = GetParam().public_key_len - 1;
  sk_len = GetParam().secret_key_len;
  ASSERT_FALSE(EVP_PKEY_kem_new_raw_key(nid, pk.data(), pk_len, sk.data(), sk_len));
  err = ERR_get_error();
  EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
  EXPECT_EQ(EVP_R_INVALID_BUFFER_SIZE, ERR_GET_REASON(err));

  pk_len = GetParam().public_key_len;
  sk_len = GetParam().secret_key_len;

  //  Failures for key validation.
  pkey_pk_new.reset(EVP_PKEY_kem_new_raw_public_key(nid, pk.data(), pk_len));
  pkey_sk_new.reset(EVP_PKEY_kem_new_raw_secret_key(nid, sk.data(), sk_len));
  pkey_new.reset(EVP_PKEY_kem_new_raw_key(nid, pk.data(), pk_len, sk.data(), sk_len));
  ASSERT_TRUE(pkey_pk_new);
  ASSERT_TRUE(pkey_sk_new);
  ASSERT_TRUE(pkey_new);

  //    Keys with one part missing should fail the check.
  ASSERT_TRUE(EVP_PKEY_kem_check_key(pkey_new.get()));
  ASSERT_FALSE(EVP_PKEY_kem_check_key(pkey_pk_new.get()));
  ASSERT_FALSE(EVP_PKEY_kem_check_key(pkey_sk_new.get()));

  //    Mismatched key pair should fail the check.
  pkey_new->pkey.kem_key->public_key[0] ^= 1;
  ASSERT_FALSE(EVP_PKEY_kem_check_key(pkey_new.get()));
}

// Perform Known Answer Test (KAT) on known KEMs.
// These tests access the deterministic EVP APIs for KeyGen and Encapsulation.
// To perform KATs in KEMs we use a DRBG seeded with a given state "seed".
// This seed is input into a DRBG, which outputs random "coins". These coins
// have been generated within the KAT files, so that DRBG seeding and calling
// can be performed outside of the library/KEM implementation.
// The "coins" provided to key generation are "keypair_coins".
// The "coins" provided to key encapsulation are "encap_coins".
TEST_P(PerKEMTest, KAT) {
  std::string kat_filepath = "crypto/";
  kat_filepath += GetParam().kat_filename;

  FileTestGTest(kat_filepath.c_str(), [&](FileTest *t) {
    std::string count;
    std::vector<uint8_t> keypair_coins, encap_coins, pk_expected,
        sk_expected, ct_expected, ss_expected;

    ASSERT_TRUE(t->GetAttribute(&count, "count"));
    ASSERT_TRUE(t->GetBytes(&keypair_coins, "keypair_coins"));
    ASSERT_TRUE(t->GetBytes(&pk_expected, "pk"));
    ASSERT_TRUE(t->GetBytes(&sk_expected, "sk"));
    ASSERT_TRUE(t->GetBytes(&encap_coins, "encap_coins"));
    ASSERT_TRUE(t->GetBytes(&ct_expected, "ct"));
    ASSERT_TRUE(t->GetBytes(&ss_expected, "ss"));

    size_t pk_len = GetParam().public_key_len;
    size_t sk_len = GetParam().secret_key_len;
    size_t ct_len = GetParam().ciphertext_len;
    size_t ss_len = GetParam().shared_secret_len;
    size_t keygen_seed_len = GetParam().keygen_seed_len;
    size_t encap_seed_len = GetParam().encaps_seed_len;

    // ---- 1. Setup the context and generate the key ----
    bssl::UniquePtr<EVP_PKEY_CTX> ctx;
    ctx = setup_ctx_and_generate_key(GetParam().nid,
                                     keypair_coins.data(),
                                     &keygen_seed_len);
    ASSERT_TRUE(ctx);

    EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx.get());
    ASSERT_TRUE(pkey);
    CMP_VEC_AND_PKEY_PUBLIC(pk_expected, pkey, pk_len);
    CMP_VEC_AND_PKEY_SECRET(sk_expected, pkey, sk_len);

    // ---- 2. Encapsulation ----
    std::vector<uint8_t> ct(ct_len);
    std::vector<uint8_t> ss(ss_len);
    ASSERT_TRUE(EVP_PKEY_encapsulate_deterministic(ctx.get(), ct.data(), &ct_len,
                                                   ss.data(), &ss_len,
                                                   encap_coins.data(),
                                                   &encap_seed_len));
    EXPECT_EQ(Bytes(ct_expected), Bytes(ct));
    EXPECT_EQ(Bytes(ss_expected), Bytes(ss));

    // ---- 3. Decapsulation ----
    ASSERT_TRUE(EVP_PKEY_decapsulate(ctx.get(), ss.data(), &ss_len, ct.data(), ct_len));
    EXPECT_EQ(Bytes(ss_expected), Bytes(ss));
  });
}

TEST_P(PerKEMTest, KeygenSeedTest) {
  // ---- 1. Setup phase: generate a context and a key ----
  // Create context of KEM type.
  bssl::UniquePtr<EVP_PKEY_CTX> ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_KEM, nullptr));
  ASSERT_TRUE(ctx);

  // Generate a key pair.
  EVP_PKEY *raw = nullptr;
  ASSERT_TRUE(EVP_PKEY_keygen_init(ctx.get()));

  // ---- 2. Test passing in a context without the KEM parameters set. ----
  size_t keygen_seed_len = GetParam().keygen_seed_len;
  std::vector<uint8_t> keygen_seed(keygen_seed_len);
  ASSERT_FALSE(EVP_PKEY_keygen_deterministic(ctx.get(), &raw,
                                             keygen_seed.data(),
                                             &keygen_seed_len));
  EXPECT_EQ(EVP_R_NO_PARAMETERS_SET, ERR_GET_REASON(ERR_peek_last_error()));

  // Setup the context with specific KEM parameters.
  ASSERT_TRUE(EVP_PKEY_CTX_kem_set_params(ctx.get(), GetParam().nid));

  // ---- 3. Test getting the lengths only ----
  keygen_seed_len = 0;
  ASSERT_TRUE(EVP_PKEY_keygen_deterministic(ctx.get(), nullptr, nullptr,
                                            &keygen_seed_len));
  EXPECT_EQ(keygen_seed_len, GetParam().keygen_seed_len);

  // ---- 4. Test failure mode on a seed len NULL ----
  keygen_seed.resize(keygen_seed_len);
  EXPECT_FALSE(EVP_PKEY_keygen_deterministic(ctx.get(), &raw, keygen_seed.data(),
                                           nullptr));
  EXPECT_EQ(ERR_R_PASSED_NULL_PARAMETER, ERR_GET_REASON(ERR_peek_last_error()));


  // ---- 5. Test failure mode on a seed len too small ----
  keygen_seed_len -= 1;
  std::vector<uint8_t> small_keygen_seed(keygen_seed_len);
  EXPECT_FALSE(EVP_PKEY_keygen_deterministic(ctx.get(), &raw,
                                             small_keygen_seed.data(),
                                             &keygen_seed_len));
  EXPECT_EQ(EVP_R_INVALID_PARAMETERS, ERR_GET_REASON(ERR_peek_last_error()));

  // ---- 6. Test failure mode on a seed len too large ----
  keygen_seed_len += 2;
  std::vector<uint8_t> big_keygen_seed(keygen_seed_len);
  EXPECT_FALSE(EVP_PKEY_keygen_deterministic(ctx.get(), &raw, big_keygen_seed.data(),
                                             &keygen_seed_len));
  EXPECT_EQ(EVP_R_INVALID_PARAMETERS, ERR_GET_REASON(ERR_peek_last_error()));

  // ---- 7. Test failure mode on a non-NULL out_pkey and NULL seed  ----
  EXPECT_FALSE(EVP_PKEY_keygen_deterministic(ctx.get(), &raw, nullptr,
                                             &keygen_seed_len));
  EXPECT_EQ(EVP_R_INVALID_PARAMETERS, ERR_GET_REASON(ERR_peek_last_error()));
}

TEST_P(PerKEMTest, EncapsSeedTest) {

  // ---- 1. Setup phase: generate a context and a key ----
  bssl::UniquePtr<EVP_PKEY_CTX> ctx;
  ctx = setup_ctx_and_generate_key(GetParam().nid, nullptr, nullptr);
  ASSERT_TRUE(ctx);

  // ---- 2. Test getting the lengths only ----
  size_t ct_len;
  size_t ss_len;
  size_t es_len;

  ASSERT_TRUE(EVP_PKEY_encapsulate_deterministic(
      ctx.get(), nullptr, &ct_len, nullptr, &ss_len, nullptr, &es_len));
  EXPECT_EQ(ct_len, GetParam().ciphertext_len);
  EXPECT_EQ(ss_len, GetParam().shared_secret_len);
  EXPECT_EQ(es_len, GetParam().encaps_seed_len);

  std::vector<uint8_t> ct(ct_len);
  std::vector<uint8_t> ss(ss_len);
  std::vector<uint8_t> es(es_len);

  // ---- 3. Test calling encapsulate with different lengths ----
  // Set ct length to be less than expected -- should fail.
  ct_len = GetParam().ciphertext_len - 1;
  ASSERT_FALSE(EVP_PKEY_encapsulate_deterministic(ctx.get(), ct.data(), &ct_len,
                                                  ss.data(), &ss_len, es.data(),
                                                  &es_len));
  EXPECT_EQ(EVP_R_BUFFER_TOO_SMALL, ERR_GET_REASON(ERR_peek_last_error()));

  // Set ct length to be greater than expected -- should succeed because
  // it's ok to provide buffer that's larger than needed.
  ct_len = GetParam().ciphertext_len + 1;
  ASSERT_TRUE(EVP_PKEY_encapsulate_deterministic(ctx.get(), ct.data(), &ct_len,
                                                 ss.data(), &ss_len, es.data(),
                                                 &es_len));
  EXPECT_EQ(ct_len, GetParam().ciphertext_len);

  // Set ss length to be less than expected -- should fail.
  ct_len = GetParam().ciphertext_len;
  ss_len = GetParam().shared_secret_len - 1;
  ASSERT_FALSE(EVP_PKEY_encapsulate_deterministic(ctx.get(), ct.data(), &ct_len,
                                                  ss.data(), &ss_len, es.data(),
                                                  &es_len));
  EXPECT_EQ(EVP_R_BUFFER_TOO_SMALL, ERR_GET_REASON(ERR_peek_last_error()));

  // Set ss length to be greater than expected -- should succeed because
  // it's ok to provide buffer that's larger than needed.
  ss_len = GetParam().shared_secret_len + 1;
  ASSERT_TRUE(EVP_PKEY_encapsulate_deterministic(ctx.get(), ct.data(), &ct_len,
                                                 ss.data(), &ss_len, es.data(),
                                                 &es_len));
  EXPECT_EQ(ss_len, GetParam().shared_secret_len);

  // ---- 4. Test failure mode on seed being NULL ----
  ASSERT_FALSE(EVP_PKEY_encapsulate_deterministic(
      ctx.get(), ct.data(), &ct_len, ss.data(), &ss_len, nullptr, &es_len));
  EXPECT_EQ(EVP_R_MISSING_PARAMETERS, ERR_GET_REASON(ERR_peek_last_error()));

  // ---- 5. Test failure mode on a seed len NULL ----
  ASSERT_FALSE(EVP_PKEY_encapsulate_deterministic(
      ctx.get(), ct.data(), &ct_len, ss.data(), &ss_len, es.data(), nullptr));
  EXPECT_EQ(ERR_R_PASSED_NULL_PARAMETER, ERR_GET_REASON(ERR_peek_last_error()));

  // ---- 6. Test failure mode on a seed len too small ----
  es_len -= 1;
  ASSERT_FALSE(EVP_PKEY_encapsulate_deterministic(
      ctx.get(), ct.data(), &ct_len, ss.data(), &ss_len, es.data(), &es_len));
  EXPECT_EQ(EVP_R_INVALID_PARAMETERS, ERR_GET_REASON(ERR_peek_last_error()));
}

static const struct KnownKEM kMLKEMs[] = {
    {"MLKEM512", NID_MLKEM512, 800, 1632, 768, 32, 64, 32, "fipsmodule/ml_kem/kat/mlkem512.txt"},
    {"MLKEM768", NID_MLKEM768, 1184, 2400, 1088, 32, 64, 32, "fipsmodule/ml_kem/kat/mlkem768.txt"},
    {"MLKEM1024", NID_MLKEM1024, 1568, 3168, 1568, 32, 64, 32, "fipsmodule/ml_kem/kat/mlkem1024.txt"},
};

class PerMLKEMTest : public testing::TestWithParam<KnownKEM> {};

INSTANTIATE_TEST_SUITE_P(All, PerMLKEMTest, testing::ValuesIn(kMLKEMs),
                         [](const testing::TestParamInfo<KnownKEM> &params)
                             -> std::string { return params.param.name; });

TEST_P(PerMLKEMTest, InputValidation) {
  // ---- 1. Setup phase: generate a context and a key ----
  bssl::UniquePtr<EVP_PKEY_CTX> ctx;
  ctx = setup_ctx_and_generate_key(GetParam().nid, nullptr, nullptr);
  ASSERT_TRUE(ctx);

  // ---- 2. Test basic encapsulation flow ----
  // Alloc ciphertext and shared secret with the expected lengths.
  size_t ct_len = GetParam().ciphertext_len;
  size_t ss_len = GetParam().shared_secret_len;
  std::vector<uint8_t> ct(ct_len);
  std::vector<uint8_t> ss(ss_len);

  // Encapsulate.
  ASSERT_TRUE(EVP_PKEY_encapsulate(ctx.get(), ct.data(), &ct_len, ss.data(), &ss_len));

  // ---- 3. Test invalid public key ----
  // FIPS 203 Section 7.2 Encapsulation key check (Modulus check).
  // Invalidate the key by forcing a coefficient out of range
  // (save the original values to reset later).
  uint8_t tmp0 = ctx->pkey->pkey.kem_key->public_key[0];
  uint8_t tmp1 = ctx->pkey->pkey.kem_key->public_key[1];
  ctx->pkey->pkey.kem_key->public_key[0] = 0xff;
  ctx->pkey->pkey.kem_key->public_key[1] = 0xff;

  ASSERT_FALSE(
      EVP_PKEY_encapsulate(ctx.get(), ct.data(), &ct_len, ss.data(), &ss_len));

  // Reset the public key and make sure encapsulation/decapsulation succeeds.
  ctx->pkey->pkey.kem_key->public_key[0] = tmp0;
  ctx->pkey->pkey.kem_key->public_key[1] = tmp1;

  std::vector<uint8_t> ss_expected(ss_len); // The shared secret.
  ASSERT_TRUE(EVP_PKEY_encapsulate(ctx.get(), ct.data(), &ct_len, ss.data(), &ss_len));
  ASSERT_TRUE(EVP_PKEY_decapsulate(ctx.get(), ss_expected.data(), &ss_len, ct.data(), ct_len));
  EXPECT_EQ(Bytes(ss_expected), Bytes(ss));

  // ---- 4. Test invalid secret key ----
  // FIPS 203 Section 7.3 Decapsulation key check (Hash check).
  // Invalidate the key by changing the hash of the public key within the secret key.
  // The 32-byte hash is stored right before the last 32 bytes of the secret key.
  ctx->pkey->pkey.kem_key->secret_key[GetParam().secret_key_len - 64] ^= 1;
  ASSERT_FALSE(EVP_PKEY_decapsulate(ctx.get(), ss_expected.data(), &ss_len, ct.data(), ct_len));
}

struct dummy_cb_app_data {
  bool state;
};

// Dummy callback function used for testing.
static int dummy_gen_cb(EVP_PKEY_CTX *ctx) {
  // Get the application-specific data.
  auto *app_data =
      static_cast<dummy_cb_app_data *>(EVP_PKEY_CTX_get_app_data(ctx));
  EXPECT_TRUE(app_data);

  app_data->state = true;

  return 1;  // Return success (1).
}

TEST(EVPExtraTest, KeygenCallbacks) {
  bssl::UniquePtr<EVP_PKEY_CTX> ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr));
  ASSERT_TRUE(ctx);

  // Check the initial values of |ctx->keygen_info|.
  int keygen_info = EVP_PKEY_CTX_get_keygen_info(ctx.get(), -1);
  ASSERT_EQ(keygen_info, EVP_PKEY_CTX_KEYGEN_INFO_COUNT);
  for (int i = 0; i < keygen_info; i++) {
    EXPECT_EQ(EVP_PKEY_CTX_get_keygen_info(ctx.get(), i), 0);
  }

  // Generating an RSA key would have triggered the callback.
  EVP_PKEY *pkey = EVP_PKEY_new();
  ASSERT_EQ(EVP_PKEY_keygen_init(ctx.get()), 1);
  ASSERT_TRUE(EVP_PKEY_keygen(ctx.get(), &pkey));
  ASSERT_TRUE(pkey);

  // Verify that |ctx->keygen_info| has not been updated since a callback hasn't
  // been set.
  for (int i = 0; i < keygen_info; i++) {
    EXPECT_EQ(EVP_PKEY_CTX_get_keygen_info(ctx.get(), i), 0);
  }

  // Now we set the application data and callback.
  dummy_cb_app_data app_data{false};
  EVP_PKEY_CTX_set_app_data(ctx.get(), &app_data);
  EVP_PKEY_CTX_set_cb(ctx.get(), dummy_gen_cb);
  EXPECT_FALSE(app_data.state);

  // Call key generation again to trigger the callback.
  ASSERT_TRUE(EVP_PKEY_keygen(ctx.get(), &pkey));
  ASSERT_TRUE(pkey);
  bssl::UniquePtr<EVP_PKEY> ptr(pkey);

  // The callback function should set the state to true. The contents of
  // |ctx->keygen_info| will only be populated once the callback has been set.
  EXPECT_TRUE(app_data.state);
  for (int i = 0; i < keygen_info; i++) {
    EXPECT_GT(EVP_PKEY_CTX_get_keygen_info(ctx.get(), i), 0);
  }
}

struct ParamgenCBParam {
  const char* name;
  int pkey_type;
  const char* setup_command;
  const char* setup_arg;
  int keygen_info_0;
  int keygen_into_1;
};

static const ParamgenCBParam paramgenCBparams[] = {
  // DH_generate_parameters_ex makes a final call to `BN_GENCB_call(cb, 3, 0)`
  {"DH", EVP_PKEY_DH, "dh_paramgen_prime_len", "512", 3, 0},
  // dsa_internal_paramgen makes a final call to `BN_GENCB_call(cb, 3, 1))`
  {"DSA", EVP_PKEY_DSA, "dsa_paramgen_bits", "512", 3, 1},
};

class PerParamgenCBTest : public testing::TestWithParam<ParamgenCBParam> {};

INSTANTIATE_TEST_SUITE_P(All, PerParamgenCBTest, testing::ValuesIn(paramgenCBparams),
                         [](const testing::TestParamInfo<ParamgenCBParam> &params)
                             -> const char* { return params.param.name; });

TEST_P(PerParamgenCBTest, ParamgenCallbacks) {
  bssl::UniquePtr<EVP_PKEY_CTX> ctx(EVP_PKEY_CTX_new_id(GetParam().pkey_type, nullptr));
  ASSERT_TRUE(ctx);

  // Check the initial values of |ctx->keygen_info|.
  int keygen_info = EVP_PKEY_CTX_get_keygen_info(ctx.get(), -1);
  ASSERT_EQ(keygen_info, EVP_PKEY_CTX_KEYGEN_INFO_COUNT);
  for (int i = 0; i < keygen_info; i++) {
    EXPECT_EQ(EVP_PKEY_CTX_get_keygen_info(ctx.get(), i), 0);
  }


  // Generating an DH params will trigger the callback.
  ASSERT_EQ(EVP_PKEY_paramgen_init(ctx.get()), 1);
  ASSERT_TRUE(EVP_PKEY_CTX_ctrl_str(ctx.get(), GetParam().setup_command, GetParam().setup_arg));
  {
    EVP_PKEY *pkey = EVP_PKEY_new();
    ASSERT_TRUE(pkey);
    ASSERT_TRUE(EVP_PKEY_paramgen(ctx.get(), &pkey));
    EVP_PKEY_free(pkey);
  }

  // Verify that |ctx->keygen_info| has not been updated since a callback hasn't
  // been set.
  for (int i = 0; i < keygen_info; i++) {
    EXPECT_EQ(EVP_PKEY_CTX_get_keygen_info(ctx.get(), i), 0);
  }

  // Now we set the application data and callback.
  dummy_cb_app_data app_data{false};
  EVP_PKEY_CTX_set_app_data(ctx.get(), &app_data);
  EVP_PKEY_CTX_set_cb(ctx.get(), dummy_gen_cb);
  EXPECT_FALSE(app_data.state);

  // Call key generation again to trigger the callback.
  {
    EVP_PKEY *pkey = EVP_PKEY_new();
    ASSERT_TRUE(pkey);
    ASSERT_TRUE(EVP_PKEY_paramgen(ctx.get(), &pkey));
    EVP_PKEY_free(pkey);
  }

  // The callback function should set the state to true. The contents of
  // |ctx->keygen_info| will only be populated once the callback has been set.
  EXPECT_TRUE(app_data.state);

  for (int i = 0; i < keygen_info; i++) {
    if(i == 0) {
      EXPECT_EQ(EVP_PKEY_CTX_get_keygen_info(ctx.get(), i), GetParam().keygen_info_0);
    } else {
      EXPECT_EQ(EVP_PKEY_CTX_get_keygen_info(ctx.get(), i), GetParam().keygen_into_1);
    }
  }
}

static bssl::UniquePtr<EVP_PKEY> dsa_paramgen(int nbits, const EVP_MD *md,
                                              bool copy) {
  bssl::UniquePtr<EVP_PKEY> params(nullptr);
  EVP_PKEY *pkey_raw = NULL;

  auto maybe_copy = [&](bssl::UniquePtr<EVP_PKEY_CTX> *ctx) -> bool {
    if (copy) {
      ctx->reset(EVP_PKEY_CTX_dup(ctx->get()));
    }
    return *ctx != nullptr;
  };

  // Construct a EVP_PKEY_CTX
  bssl::UniquePtr<EVP_PKEY_CTX> ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_DSA, nullptr));
  if (ctx && maybe_copy(&ctx) &&
      1 == EVP_PKEY_paramgen_init(ctx.get()) &&
      1 == EVP_PKEY_CTX_set_dsa_paramgen_bits(ctx.get(), nbits) &&
      1 == EVP_PKEY_CTX_set_dsa_paramgen_md(ctx.get(), md) &&
      1 == EVP_PKEY_paramgen(ctx.get(), &pkey_raw)) {
    params.reset(pkey_raw);
  }
  return params;
}

static bssl::UniquePtr<EVP_PKEY> dsa_keygen(bssl::UniquePtr<EVP_PKEY> &params,
                                            bool copy) {
  bssl::UniquePtr<EVP_PKEY> pkey(nullptr);
  EVP_PKEY *pkey_raw = nullptr;

  auto maybe_copy = [&](bssl::UniquePtr<EVP_PKEY_CTX> *ctx) -> bool {
    if (copy) {
      ctx->reset(EVP_PKEY_CTX_dup(ctx->get()));
    }
    return *ctx != nullptr;
  };

  bssl::UniquePtr<EVP_PKEY_CTX> ctx(EVP_PKEY_CTX_new(params.get(), nullptr));
  if (ctx &&
      1 == EVP_PKEY_keygen_init(ctx.get()) && maybe_copy(&ctx) &&
      1 == EVP_PKEY_keygen(ctx.get(), &pkey_raw)) {
    pkey.reset(pkey_raw);
  }
  return pkey;
}

static bssl::UniquePtr<EVP_PKEY> dsa_public_key(
    bssl::UniquePtr<EVP_PKEY> &private_key) {
  bssl::UniquePtr<EVP_PKEY> pkey(nullptr);
  bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
  if (bio &&
      1 == PEM_write_bio_PUBKEY(bio.get(), private_key.get())) {
    pkey.reset(PEM_read_bio_PUBKEY(bio.get(), nullptr, nullptr, nullptr));
  }
  return pkey;
}

TEST(EVPExtraTest, DSAKeygen) {
  for (bool copy : {false, true}) {
    SCOPED_TRACE(copy);

    bssl::UniquePtr<EVP_PKEY> params = dsa_paramgen(512, EVP_sha1(), copy);
    ASSERT_TRUE(params);
    const DSA* params_dsa = EVP_PKEY_get0_DSA(params.get());
    ASSERT_TRUE(params_dsa);
    bssl::UniquePtr<EVP_PKEY> pkey1 = dsa_keygen(params, copy);
    ASSERT_TRUE(pkey1);

    EXPECT_EQ(EVP_PKEY_id(pkey1.get()), EVP_PKEY_DSA);
    const DSA *key1_dsa = EVP_PKEY_get0_DSA(pkey1.get());
    // Parameters P, Q and G are shared
    EXPECT_EQ(0, BN_cmp(DSA_get0_p(key1_dsa), DSA_get0_p(params_dsa)));
    EXPECT_EQ(0, BN_cmp(DSA_get0_q(key1_dsa), DSA_get0_q(params_dsa)));
    EXPECT_EQ(0, BN_cmp(DSA_get0_g(key1_dsa), DSA_get0_g(params_dsa)));

    EXPECT_TRUE(DSA_get0_pub_key(key1_dsa));
    EXPECT_TRUE(DSA_get0_priv_key(key1_dsa));
    EXPECT_EQ(1, EVP_PKEY_cmp_parameters(params.get(), pkey1.get()));
    EXPECT_EQ(0, EVP_PKEY_cmp(params.get(), pkey1.get()));

    // Generate a second key.
    bssl::UniquePtr<EVP_PKEY> pkey2 = dsa_keygen(params, copy);
    ASSERT_TRUE(pkey2);

    const DSA *key2_dsa = EVP_PKEY_get0_DSA(pkey2.get());
    EXPECT_EQ(0, BN_cmp(DSA_get0_p(key1_dsa), DSA_get0_p(key2_dsa)));
    EXPECT_EQ(0, BN_cmp(DSA_get0_q(key1_dsa), DSA_get0_q(key2_dsa)));
    EXPECT_EQ(0, BN_cmp(DSA_get0_g(key1_dsa), DSA_get0_g(key2_dsa)));
    EXPECT_TRUE(DSA_get0_pub_key(key1_dsa));
    EXPECT_TRUE(DSA_get0_priv_key(key1_dsa));

    EXPECT_EQ(1, EVP_PKEY_cmp_parameters(params.get(), pkey2.get()));
    EXPECT_EQ(1, EVP_PKEY_cmp_parameters(pkey1.get(), pkey2.get()));
    EXPECT_EQ(0, EVP_PKEY_cmp(pkey1.get(), pkey2.get()));
  }
}

TEST(EVPExtraTest, DSAParamgen) {
  std::vector<std::pair<int, const EVP_MD*>> test_data(
      {{768, EVP_sha1()}, {2048, EVP_sha224()}, {512, EVP_sha256()}});

  for (std::pair<int, const EVP_MD*> plgen : test_data) {
    const int nbits = plgen.first;
    const EVP_MD* digest = plgen.second;
    // Construct a EVP_PKEY_CTX
    bssl::UniquePtr<EVP_PKEY_CTX> ctx(
        EVP_PKEY_CTX_new_id(EVP_PKEY_DSA, nullptr));
    ASSERT_TRUE(ctx);
    // Initialize for paramgen
    ASSERT_TRUE(EVP_PKEY_paramgen_init(ctx.get()));
    // Set the prime nbits
    ASSERT_TRUE(EVP_PKEY_CTX_set_dsa_paramgen_bits(ctx.get(), nbits));
    // Set the digest
    ASSERT_TRUE(EVP_PKEY_CTX_set_dsa_paramgen_md(ctx.get(), digest));

    EVP_PKEY *raw_pkey = NULL;
    // Generate the parameters
    ASSERT_TRUE(EVP_PKEY_paramgen(ctx.get(), &raw_pkey));
    bssl::UniquePtr<EVP_PKEY> pkey(raw_pkey);
    ASSERT_TRUE(pkey);

    const DSA* dsa = EVP_PKEY_get0_DSA(pkey.get());
    ASSERT_TRUE(dsa);
    const BIGNUM* p = DSA_get0_p(dsa);
    ASSERT_TRUE(p);
    unsigned p_size = BN_num_bits(p);
    ASSERT_EQ(p_size, (unsigned)nbits);

    const BIGNUM* q = DSA_get0_q(dsa);
    ASSERT_TRUE(q);
    unsigned q_size = BN_num_bits(q);
    ASSERT_EQ(q_size, 8*(unsigned)EVP_MD_size(digest));
  }

  // Test error conditions
  // Construct a EVP_PKEY_CTX
  bssl::UniquePtr<EVP_PKEY_CTX> ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_DSA, nullptr));
  ASSERT_TRUE(ctx);
  // Initialize for paramgen
  ASSERT_TRUE(EVP_PKEY_paramgen_init(ctx.get()));
  // Set the prime length
  ASSERT_NE(EVP_PKEY_CTX_set_dsa_paramgen_bits(ctx.get(), 511), 1);
  // Set the generator
  ASSERT_NE(EVP_PKEY_CTX_set_dsa_paramgen_md(ctx.get(), EVP_md5()), 1);
}

TEST(EVPExtraTest, DSASignDigestVerify) {
  bssl::UniquePtr<EVP_PKEY> params = dsa_paramgen(512, EVP_sha1(), false);
  ASSERT_TRUE(params);

  bssl::UniquePtr<EVP_PKEY> private_key = dsa_keygen(params, false);
  ASSERT_TRUE(private_key);

  const char data[] = "Sign Me!";
  const size_t data_len = strnlen(data, 9);
  uint8_t digest[32] = {0};
  std::vector<uint8_t> sig;
  size_t siglen = 0;
  ASSERT_TRUE(SHA1((uint8_t*)data, data_len, digest));
  {
    bssl::UniquePtr<EVP_PKEY_CTX> ctx(EVP_PKEY_CTX_new(private_key.get(), nullptr));
    ASSERT_TRUE(ctx);
    ASSERT_TRUE(EVP_PKEY_sign_init(ctx.get()));
    ASSERT_EQ(1, EVP_PKEY_sign(ctx.get(), NULL, &siglen, digest, 32));
    ASSERT_GT(siglen, (size_t)0);
    sig.resize(siglen);
    ASSERT_EQ(1, EVP_PKEY_sign(ctx.get(), sig.data(), &siglen, digest, 32));
  }
  // This intentionally does not use EVP_PKEY_verify to help ensure the
  // equivalence of using different APIs for the same purpose.
  bssl::UniquePtr<EVP_PKEY> public_key = dsa_public_key(private_key);
  {
    bssl::UniquePtr<EVP_MD_CTX> md_ctx(EVP_MD_CTX_new());
    ASSERT_EQ(1, EVP_DigestVerifyInit(md_ctx.get(), nullptr, EVP_sha1(), nullptr, public_key.get()));
    ASSERT_EQ(1, EVP_DigestVerifyUpdate(md_ctx.get(), data, data_len));
    ASSERT_EQ(1, EVP_DigestVerifyFinal(md_ctx.get(), sig.data(), siglen));
  }

}

TEST(EVPExtraTest, DSADigestSignFinalVerify) {
  bssl::UniquePtr<EVP_PKEY> params = dsa_paramgen(512, EVP_sha1(), false);
  ASSERT_TRUE(params);

  bssl::UniquePtr<EVP_PKEY> private_key = dsa_keygen(params, false);
  ASSERT_TRUE(private_key);

  const char data[] = "Sign Me!";
  const size_t data_len = strnlen(data, 9);
  std::vector<uint8_t> sig;
  size_t siglen = 0;

  {
    EVP_PKEY_CTX* raw_pctx = nullptr;
    const EVP_MD* raw_md = nullptr;
    
    bssl::UniquePtr<EVP_MD_CTX> md_ctx(EVP_MD_CTX_new());
    ASSERT_TRUE(md_ctx);
    ASSERT_NE(1, EVP_DigestSignInit(md_ctx.get(), &raw_pctx, EVP_md5(), nullptr, private_key.get()));
    // md_ctx takes ownership of raw_pctx
    ASSERT_EQ(1, EVP_DigestSignInit(md_ctx.get(), &raw_pctx, EVP_sha256(), nullptr, private_key.get()));

    ASSERT_EQ(1, EVP_PKEY_CTX_get_signature_md(raw_pctx, &raw_md));
    ASSERT_EQ(EVP_sha256(), raw_md);

    ASSERT_EQ(1, EVP_DigestSignUpdate(md_ctx.get(), data, data_len));
    ASSERT_EQ(1, EVP_DigestSignFinal(md_ctx.get(), nullptr, &siglen));
    sig.resize(siglen);
    ASSERT_EQ(1, EVP_DigestSignFinal(md_ctx.get(), sig.data(), &siglen));
  }
  // This intentionally does not use EVP_DigestVerify to help ensure the
  // equivalence of using different APIs for the same purpose.
  uint8_t digest[32] = {0};
  ASSERT_TRUE(SHA256((uint8_t*)data, data_len, digest));
  bssl::UniquePtr<EVP_PKEY> public_key = dsa_public_key(private_key);
  {
    bssl::UniquePtr<EVP_PKEY_CTX> ctx(EVP_PKEY_CTX_new(public_key.get(), nullptr));
    ASSERT_TRUE(ctx);
    ASSERT_TRUE(EVP_PKEY_verify_init(ctx.get()));
    ASSERT_EQ(1, EVP_PKEY_verify(ctx.get(), sig.data(), siglen, digest, 32));
  }
}

TEST(EVPExtraTest, DSADigestSignVerify) {
  bssl::UniquePtr<EVP_PKEY> params = dsa_paramgen(512, EVP_sha1(), false);
  ASSERT_TRUE(params);

  bssl::UniquePtr<EVP_PKEY> private_key = dsa_keygen(params, false);
  ASSERT_TRUE(private_key);

  const char data[] = "Sign Me!";
  const size_t data_len = strnlen(data, 9);
  std::vector<uint8_t> sig;
  size_t siglen = 0;

  {
    bssl::UniquePtr<EVP_MD_CTX> md_ctx(EVP_MD_CTX_new());
    ASSERT_TRUE(md_ctx);
    ASSERT_EQ(1, EVP_DigestSignInit(md_ctx.get(), nullptr, EVP_sha256(), nullptr, private_key.get()));
    ASSERT_EQ(1, EVP_DigestSign(md_ctx.get(), nullptr, &siglen, (const uint8_t*)data, data_len));
    sig.resize(siglen);
    ASSERT_EQ(1, EVP_DigestSign(md_ctx.get(), sig.data(), &siglen, (const uint8_t*)data, data_len));
  }

  bssl::UniquePtr<EVP_PKEY> public_key = dsa_public_key(private_key);
  {
    bssl::UniquePtr<EVP_MD_CTX> md_ctx(EVP_MD_CTX_new());
    ASSERT_TRUE(md_ctx);
    ASSERT_TRUE(EVP_DigestVerifyInit(md_ctx.get(), nullptr, EVP_sha256(), nullptr, public_key.get()));
    ASSERT_TRUE(EVP_DigestVerify(md_ctx.get(), sig.data(), siglen, (const uint8_t*)data, data_len));
  }
}

TEST(EVPExtraTest, RawKeyUnsupported) {
  static const uint8_t kKey[] = {1, 2, 3, 4};
  EXPECT_FALSE(
      EVP_PKEY_new_raw_public_key(EVP_PKEY_RSA, nullptr, kKey, sizeof(kKey)));
  EXPECT_FALSE(
      EVP_PKEY_new_raw_private_key(EVP_PKEY_RSA, nullptr, kKey, sizeof(kKey)));
}

TEST(EVPExtraTest, DSATrailingSignatureGarbage) {
  // Test case was sourced from https://github.com/C2SP/wycheproof
  const uint8_t DSA_PUB_DER[] = {
      0x30, 0x82, 0x01, 0xb6, 0x30, 0x82, 0x01, 0x2b, 0x06, 0x07, 0x2a, 0x86,
      0x48, 0xce, 0x38, 0x04, 0x01, 0x30, 0x82, 0x01, 0x1e, 0x02, 0x81, 0x81,
      0x00, 0xb3, 0x4c, 0xe9, 0xc1, 0xe7, 0x82, 0x94, 0xd3, 0x25, 0x84, 0x73,
      0x84, 0x20, 0x05, 0xd2, 0xa4, 0x8c, 0x8c, 0x56, 0x6c, 0xfc, 0xa8, 0xf8,
      0x4c, 0x06, 0x06, 0xf2, 0x52, 0x9b, 0x59, 0xa6, 0xd3, 0x8a, 0xae, 0x07,
      0x1b, 0x53, 0xbb, 0x21, 0x67, 0xea, 0xa4, 0xfc, 0x3b, 0x01, 0xfe, 0x17,
      0x6e, 0x78, 0x7e, 0x48, 0x1b, 0x60, 0x37, 0xaa, 0xc6, 0x2c, 0xbc, 0x3d,
      0x08, 0x97, 0x99, 0x53, 0x6a, 0x86, 0x9f, 0xa8, 0xcd, 0xfe, 0xa1, 0xe8,
      0xb1, 0xfd, 0x2d, 0x1c, 0xd3, 0xa3, 0x03, 0x50, 0x85, 0x9a, 0x2c, 0xd6,
      0xb3, 0xec, 0x2f, 0x9b, 0xfb, 0xb6, 0x8b, 0xb1, 0x1b, 0x4b, 0xbe, 0x2a,
      0xda, 0xa1, 0x8d, 0x64, 0xa9, 0x36, 0x39, 0x54, 0x3a, 0xe5, 0xe1, 0x62,
      0x93, 0xe3, 0x11, 0xc0, 0xcf, 0x8c, 0x8d, 0x6e, 0x18, 0x0d, 0xf0, 0x5d,
      0x08, 0xc2, 0xfd, 0x2d, 0x93, 0xd5, 0x70, 0x75, 0x1f, 0x02, 0x15, 0x00,
      0xb9, 0x0b, 0x38, 0xba, 0x0a, 0x50, 0xa4, 0x3e, 0xc6, 0x89, 0x8d, 0x3f,
      0x9b, 0x68, 0x04, 0x97, 0x77, 0xf4, 0x89, 0xb1, 0x02, 0x81, 0x80, 0x08,
      0x35, 0xaa, 0x8c, 0x35, 0x8b, 0xbf, 0x01, 0xa1, 0x84, 0x6d, 0x12, 0x06,
      0x32, 0x3f, 0xab, 0xe4, 0x08, 0xb0, 0xe9, 0x87, 0x89, 0xfc, 0xc6, 0x23,
      0x9d, 0xa1, 0x4d, 0x4b, 0x3f, 0x86, 0xc2, 0x76, 0xa8, 0xf4, 0x8a, 0xa8,
      0x5a, 0x59, 0x50, 0x7e, 0x62, 0x0a, 0xd1, 0xbc, 0x74, 0x5f, 0x0f, 0x1c,
      0xbf, 0x63, 0xec, 0x98, 0xc2, 0x29, 0xc2, 0x61, 0x0d, 0x77, 0xc6, 0x34,
      0xd1, 0x64, 0x2e, 0x40, 0x43, 0x54, 0x77, 0x16, 0x55, 0xb2, 0xd5, 0x66,
      0x2f, 0x7a, 0x45, 0x22, 0x71, 0x78, 0xce, 0x34, 0x30, 0xaf, 0x0f, 0x6b,
      0x3b, 0xb9, 0x4b, 0x52, 0xf7, 0xf5, 0x1e, 0x97, 0xba, 0xd6, 0x59, 0xb1,
      0xba, 0x06, 0x84, 0xe2, 0x08, 0xbe, 0x62, 0x4c, 0x28, 0xd8, 0x2f, 0xb1,
      0x16, 0x2f, 0x18, 0xdd, 0x9d, 0xce, 0x45, 0x21, 0x64, 0x61, 0x65, 0x4c,
      0xf3, 0x37, 0x46, 0x24, 0xd1, 0x5a, 0x8d, 0x03, 0x81, 0x84, 0x00, 0x02,
      0x81, 0x80, 0x17, 0x39, 0x31, 0xdd, 0xa3, 0x1e, 0xff, 0x32, 0xf2, 0x4b,
      0x38, 0x30, 0x91, 0xbf, 0x77, 0xea, 0xcd, 0xc6, 0xef, 0xd5, 0x57, 0x62,
      0x49, 0x11, 0xd8, 0xe9, 0xb9, 0xde, 0xbf, 0x0f, 0x25, 0x6d, 0x0c, 0xff,
      0xac, 0x55, 0x67, 0xb3, 0x3f, 0x6e, 0xaa, 0xe9, 0xd3, 0x27, 0x5b, 0xbe,
      0xd7, 0xef, 0x9f, 0x5f, 0x94, 0xc4, 0x00, 0x3c, 0x95, 0x9e, 0x49, 0xa1,
      0xed, 0x3f, 0x58, 0xc3, 0x1b, 0x21, 0xba, 0xcc, 0xc0, 0xed, 0x88, 0x40,
      0xb4, 0x61, 0x45, 0xf1, 0x21, 0xb8, 0x90, 0x6d, 0x07, 0x21, 0x29, 0xba,
      0xe0, 0x1f, 0x07, 0x19, 0x47, 0x99, 0x7e, 0x8e, 0xf7, 0x60, 0xd2, 0xd9,
      0xea, 0x21, 0xd0, 0x8a, 0x5e, 0xb7, 0xe8, 0x93, 0x90, 0xb2, 0x1a, 0x85,
      0x66, 0x47, 0x13, 0xc5, 0x49, 0xe2, 0x5f, 0xed, 0xa6, 0xe9, 0xe6, 0xc3,
      0x19, 0x70, 0x86, 0x6b, 0xdf, 0xbc, 0x8f, 0xa9, 0x81, 0xf6};
  const uint8_t MESSAGE[] = {0x31, 0x32, 0x33, 0x34, 0x30, 0x30};
  // SIGNATURE has extra bytes trailing after the ASN.1 DER encoding
  const uint8_t SIGNATURE[] = {
      0x30, 0x2d, 0x02, 0x15, 0x00, 0xaa, 0x6a, 0x25, 0x8f, 0xbf,
      0x7d, 0x90, 0xe1, 0x56, 0x14, 0x67, 0x6d, 0x37, 0x7d, 0xf8,
      0xb1, 0x0e, 0x38, 0xdb, 0x4a, 0x02, 0x14, 0x49, 0x6d, 0x52,
      0x20, 0xb5, 0xf6, 0x7d, 0x35, 0x32, 0xd1, 0xf9, 0x91, 0x20,
      0x3b, 0xc3, 0x52, 0x3b, 0x96, 0x4c, 0x3b, 0x00, 0x00};

  CBS cbs;
  CBS_init(&cbs, DSA_PUB_DER, sizeof(DSA_PUB_DER));

  bssl::UniquePtr<EVP_PKEY> pkey(EVP_parse_public_key(&cbs));
  ASSERT_EQ(EVP_PKEY_DSA, EVP_PKEY_id(pkey.get()));

  bssl::UniquePtr<DSA> dsa(EVP_PKEY_get1_DSA(pkey.get()));
  
  uint8_t digest[sizeof(SIGNATURE)] = {0};
  unsigned int digest_len = sizeof(digest);
  ASSERT_TRUE(EVP_Digest(MESSAGE, sizeof(MESSAGE), digest, &digest_len, EVP_sha1(), nullptr));

  EXPECT_EQ(-1, DSA_verify(0, digest, sizeof(digest), SIGNATURE, sizeof(SIGNATURE), dsa.get()));

  int valid = 0;
  EXPECT_EQ(0, DSA_check_signature(&valid, digest, sizeof(digest), SIGNATURE, sizeof(SIGNATURE), dsa.get()));
  EXPECT_EQ(0, valid);

  bssl::UniquePtr<EVP_PKEY_CTX> ctx(EVP_PKEY_CTX_new(pkey.get(), nullptr));
  ASSERT_TRUE(ctx);
  ASSERT_TRUE(EVP_PKEY_verify_init(ctx.get()));

  EXPECT_FALSE(EVP_PKEY_verify(ctx.get(), SIGNATURE, sizeof(SIGNATURE), digest, sizeof(digest)));

  bssl::UniquePtr<EVP_MD_CTX> md_ctx(EVP_MD_CTX_new());
  ASSERT_TRUE(md_ctx);

  ASSERT_TRUE(EVP_DigestVerifyInit(md_ctx.get(), nullptr, EVP_sha1(), nullptr, pkey.get()));
  EXPECT_FALSE(EVP_DigestVerify(md_ctx.get(), SIGNATURE, sizeof(SIGNATURE), MESSAGE, sizeof(MESSAGE)));
}

// Test that setting a key to type none will clear it. Some calling code has
// unit tests that rely on this, usually as part of a roundabout way to get a
// key of the "wrong" type to test with. (In reality, |EVP_PKEY_new| will
// produce the same object.)
TEST(EVPExtraTest, SetNoneClearsKey) {
  bssl::UniquePtr<EVP_PKEY> pkey = LoadExampleRSAKey();
  ASSERT_TRUE(pkey);
  // EVP_PKEY_NONE is not a known type, so this should fail.
  EXPECT_FALSE(EVP_PKEY_set_type(pkey.get(), EVP_PKEY_NONE));
  // However, it still resets the key to the initial state.
  EXPECT_EQ(EVP_PKEY_id(pkey.get()), EVP_PKEY_NONE);
  // Calling operations on the |EVP_PKEY| should cleanly fail.
  EXPECT_EQ(EVP_PKEY_bits(pkey.get()), 0);
}

// EVP_PKEY_assign_FOO with NULL should fail without changing the key type.
TEST(EVPExtraTest, NoHalfEmptyKeys) {
  bssl::UniquePtr<EVP_PKEY> pkey(EVP_PKEY_new());
  ASSERT_TRUE(pkey);

  EXPECT_FALSE(EVP_PKEY_set1_RSA(pkey.get(), nullptr));
  EXPECT_EQ(EVP_PKEY_id(pkey.get()), EVP_PKEY_NONE);

  EXPECT_FALSE(EVP_PKEY_set1_EC_KEY(pkey.get(), nullptr));
  EXPECT_EQ(EVP_PKEY_id(pkey.get()), EVP_PKEY_NONE);

  EXPECT_FALSE(EVP_PKEY_set1_DH(pkey.get(), nullptr));
  EXPECT_EQ(EVP_PKEY_id(pkey.get()), EVP_PKEY_NONE);

  EXPECT_FALSE(EVP_PKEY_set1_DSA(pkey.get(), nullptr));
  EXPECT_EQ(EVP_PKEY_id(pkey.get()), EVP_PKEY_NONE);
}

// Test that |EC_KEY|s using custom curves can be wrapped in |EVP_PKEY|. Callers
// should not follow this code. This is maintained and tested only for
// compatibility with one legacy application, and supported in only a limited
// form. (E.g. such keys cannot be serialized.)
TEST(EVPExtraTest, CustomCurve) {
  // Coefficients for brainpoolp256r1, not supported by BoringSSL.
  static const char kP[] =
      "a9fb57dba1eea9bc3e660a909d838d726e3bf623d52620282013481d1f6e5377";
  static const char kA[] =
      "7d5a0975fc2c3057eef67530417affe7fb8055c126dc5c6ce94a4b44f330b5d9";
  static const char kB[] =
      "26dc5c6ce94a4b44f330b5d9bbd77cbf958416295cf7e1ce6bccdc18ff8c07b6";
  static const char kX[] =
      "8bd2aeb9cb7e57cb2c4b482ffc81b7afb9de27e1e3bd23c23a4453bd9ace3262";
  static const char kY[] =
      "547ef835c3dac4fd97f8461a14611dc9c27745132ded8e545c1d54c72f046997";
  static const char kN[] =
      "a9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e82974856a7";
  static const char kD[] =
      "0da21d76fed40dd82ac3314cce91abb585b5c4246e902b238a839609ea1e7ce1";
  static const char kQX[] =
      "3a55e0341cab50452fe27b8a87e4775dec7a9daca94b0d84ad1e9f85b53ea513";
  static const char kQY[] =
      "40088146b33bbbe81b092b41146774b35dd478cf056437cfb35ef0df2d269339";

  // Construct a custom group.
  bssl::UniquePtr<BIGNUM> p = HexToBIGNUM(kP), a = HexToBIGNUM(kA),
                          b = HexToBIGNUM(kB), x = HexToBIGNUM(kX),
                          y = HexToBIGNUM(kY), n = HexToBIGNUM(kN),
                          d = HexToBIGNUM(kD), qx = HexToBIGNUM(kQX),
                          qy = HexToBIGNUM(kQY);
  ASSERT_TRUE(p && a && b && x && y && n && d && qx && qy);
  bssl::UniquePtr<EC_GROUP> group(
      EC_GROUP_new_curve_GFp(p.get(), a.get(), b.get(), nullptr));
  ASSERT_TRUE(group);
  bssl::UniquePtr<EC_POINT> g(EC_POINT_new(group.get()));
  ASSERT_TRUE(g);
  ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp(group.get(), g.get(), x.get(),
                                                  y.get(), nullptr));
  ASSERT_TRUE(
      EC_GROUP_set_generator(group.get(), g.get(), n.get(), BN_value_one()));

  // Generate a key with it.
  bssl::UniquePtr<EC_KEY> ec_key(EC_KEY_new());
  ASSERT_TRUE(ec_key);
  ASSERT_TRUE(EC_KEY_set_group(ec_key.get(), group.get()));
  ASSERT_TRUE(EC_KEY_generate_key(ec_key.get()));

  // Wrap it in an |EVP_PKEY|.
  bssl::UniquePtr<EVP_PKEY> pkey(EVP_PKEY_new());
  ASSERT_TRUE(pkey);
  ASSERT_TRUE(EVP_PKEY_set1_EC_KEY(pkey.get(), ec_key.get()));

  // Signing should work.
  static const uint8_t msg[] = "hello";
  bssl::ScopedEVP_MD_CTX ctx;
  ASSERT_TRUE(EVP_DigestSignInit(ctx.get(), nullptr, EVP_sha256(), nullptr,
                                 pkey.get()));
  std::vector<uint8_t> sig(EVP_PKEY_size(pkey.get()));
  size_t len = sig.size();
  ASSERT_TRUE(
      EVP_DigestSign(ctx.get(), sig.data(), &len, msg, sizeof(msg) - 1));
  sig.resize(len);

  // Verifying should work.
  ctx.Reset();
  ASSERT_TRUE(EVP_DigestVerifyInit(ctx.get(), nullptr, EVP_sha256(), nullptr,
                                   pkey.get()));
  ASSERT_TRUE(EVP_DigestVerify(ctx.get(), sig.data(), sig.size(), msg,
                               sizeof(msg) - 1));

  // We will not serialize arbitrary groups, so serialization should fail.
  bssl::ScopedCBB cbb;
  ASSERT_TRUE(CBB_init(cbb.get(), 0));
  EXPECT_FALSE(EVP_marshal_public_key(cbb.get(), pkey.get()));
  cbb.Reset();
  ASSERT_TRUE(CBB_init(cbb.get(), 0));
  EXPECT_FALSE(EVP_marshal_private_key(cbb.get(), pkey.get()));
}

// See P425780141.
// Minimal RFC 5958 v2 OneAsymmetricKey for Ed25519 with an empty
// [0] attributes SET and a [1] publicKey. Hand-rolled so the on-the-wire
// attributes tag is the conformant 0xA0 (context-specific | constructed | 0).
//
// SEQUENCE {
//   INTEGER 1                           -- v2
//   SEQUENCE { OID 1.3.101.112 }        -- Ed25519
//   OCTET STRING { OCTET STRING seed }  -- 32-byte seed
//   [0] { }                             -- empty Attributes (0xA0 0x00)
//   [1] { 00 || pubkey }                -- 33 bytes, leading 0 pad
// }
TEST(EVPExtraTest, Ed25519PKCS8v2WithAttributes) {
  static const uint8_t kDER[] = {
    0x30, 0x53,                                     // SEQUENCE, len 0x51
      0x02, 0x01, 0x01,                             // version = 1 (v2)
      0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70,     // AlgId { OID 1.3.101.112 }
      0x04, 0x22,                                   // OCTET STRING, len 0x22
        0x04, 0x20,                                 //   OCTET STRING, len 32
        0x9d, 0x61, 0xb1, 0x9d, 0xef, 0xfd, 0x5a, 0x60,
        0xba, 0x84, 0x4a, 0xf4, 0x92, 0xec, 0x2c, 0xc4,
        0x44, 0x49, 0xc5, 0x69, 0x7b, 0x32, 0x69, 0x19,
        0x70, 0x3b, 0xac, 0x03, 0x1c, 0xae, 0x7f, 0x60,
      0xa0, 0x00,                                   // [0] attributes = { } (empty SET)
      0x81, 0x21, 0x00,                             // [1] publicKey BIT STRING, 0 pad bits
        0xd7, 0x5a, 0x98, 0x01, 0x82, 0xb1, 0x0a, 0xb7,
        0xd5, 0x4b, 0xfe, 0xd3, 0xc9, 0x64, 0x07, 0x3a,
        0x0e, 0xe1, 0x72, 0xf3, 0xda, 0xa6, 0x23, 0x25,
        0xaf, 0x02, 0x1a, 0x68, 0xf7, 0x07, 0x51, 0x1a,
  };

  static const uint8_t kPublicKey[32] = {
      0xd7, 0x5a, 0x98, 0x01, 0x82, 0xb1, 0x0a, 0xb7, 0xd5, 0x4b, 0xfe,
      0xd3, 0xc9, 0x64, 0x07, 0x3a, 0x0e, 0xe1, 0x72, 0xf3, 0xda, 0xa6,
      0x23, 0x25, 0xaf, 0x02, 0x1a, 0x68, 0xf7, 0x07, 0x51, 0x1a,
  };

  CBS cbs;
  CBS_init(&cbs, kDER, sizeof(kDER));
  bssl::UniquePtr<EVP_PKEY> parsed(EVP_parse_private_key(&cbs));
  ASSERT_TRUE(parsed);
  EXPECT_EQ(CBS_len(&cbs), 0u);

  uint8_t pub[32];
  size_t pub_len = sizeof(pub);
  ASSERT_TRUE(EVP_PKEY_get_raw_public_key(parsed.get(), pub, &pub_len));
  EXPECT_EQ(Bytes(pub, pub_len), Bytes(kPublicKey));
}
