#include <err.h>
#include <stdio.h>
#include <string.h>
#include <openssl/x509.h>
static const struct x509_name_legacy {
const char *compat;
const char *oneline;
const uint8_t der[255];
size_t der_len;
} x509_name_legacy_test[] = {
{
.compat =
"C=HU, "
"L=Budapest, "
"O=Microsec Ltd., "
"CN=Microsec e-Szigno Root CA 2009, "
"emailAddress=info@e-szigno.hu",
.oneline =
"/C=HU"
"/L=Budapest"
"/O=Microsec Ltd."
"/CN=Microsec e-Szigno Root CA 2009"
"/emailAddress=info@e-szigno.hu",
.der = {
0x30, 0x81, 0x82, 0x31, 0x0b, 0x30, 0x09, 0x06,
0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x48, 0x55,
0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
0x07, 0x0c, 0x08, 0x42, 0x75, 0x64, 0x61, 0x70,
0x65, 0x73, 0x74, 0x31, 0x16, 0x30, 0x14, 0x06,
0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0d, 0x4d, 0x69,
0x63, 0x72, 0x6f, 0x73, 0x65, 0x63, 0x20, 0x4c,
0x74, 0x64, 0x2e, 0x31, 0x27, 0x30, 0x25, 0x06,
0x03, 0x55, 0x04, 0x03, 0x0c, 0x1e, 0x4d, 0x69,
0x63, 0x72, 0x6f, 0x73, 0x65, 0x63, 0x20, 0x65,
0x2d, 0x53, 0x7a, 0x69, 0x67, 0x6e, 0x6f, 0x20,
0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20,
0x32, 0x30, 0x30, 0x39, 0x31, 0x1f, 0x30, 0x1d,
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
0x01, 0x09, 0x01, 0x16, 0x10, 0x69, 0x6e, 0x66,
0x6f, 0x40, 0x65, 0x2d, 0x73, 0x7a, 0x69, 0x67,
0x6e, 0x6f, 0x2e, 0x68, 0x75,
},
.der_len = 133,
},
{
.compat =
"serialNumber=G63287510, "
"C=ES, "
"O=ANF Autoridad de Certificacion, "
"OU=ANF CA Raiz, "
"CN=ANF Secure Server Root CA",
.oneline =
"/serialNumber=G63287510"
"/C=ES"
"/O=ANF Autoridad de Certificacion"
"/OU=ANF CA Raiz"
"/CN=ANF Secure Server Root CA",
.der = {
0x30, 0x81, 0x84, 0x31, 0x12, 0x30, 0x10, 0x06,
0x03, 0x55, 0x04, 0x05, 0x13, 0x09, 0x47, 0x36,
0x33, 0x32, 0x38, 0x37, 0x35, 0x31, 0x30, 0x31,
0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
0x13, 0x02, 0x45, 0x53, 0x31, 0x27, 0x30, 0x25,
0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x1e, 0x41,
0x4e, 0x46, 0x20, 0x41, 0x75, 0x74, 0x6f, 0x72,
0x69, 0x64, 0x61, 0x64, 0x20, 0x64, 0x65, 0x20,
0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
0x61, 0x63, 0x69, 0x6f, 0x6e, 0x31, 0x14, 0x30,
0x12, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0b,
0x41, 0x4e, 0x46, 0x20, 0x43, 0x41, 0x20, 0x52,
0x61, 0x69, 0x7a, 0x31, 0x22, 0x30, 0x20, 0x06,
0x03, 0x55, 0x04, 0x03, 0x13, 0x19, 0x41, 0x4e,
0x46, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65,
0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20,
0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41,
},
.der_len = 135,
},
{
.compat =
"C=GB, "
"ST=Greater Manchester, "
"L=Salford, "
"O=COMODO CA Limited, "
"CN=COMODO Certification Authority",
.oneline =
"/C=GB"
"/ST=Greater Manchester"
"/L=Salford"
"/O=COMODO CA Limited"
"/CN=COMODO Certification Authority",
.der = {
0x30, 0x81, 0x81, 0x31, 0x0b, 0x30, 0x09, 0x06,
0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42,
0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04,
0x08, 0x13, 0x12, 0x47, 0x72, 0x65, 0x61, 0x74,
0x65, 0x72, 0x20, 0x4d, 0x61, 0x6e, 0x63, 0x68,
0x65, 0x73, 0x74, 0x65, 0x72, 0x31, 0x10, 0x30,
0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x07,
0x53, 0x61, 0x6c, 0x66, 0x6f, 0x72, 0x64, 0x31,
0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x0a,
0x13, 0x11, 0x43, 0x4f, 0x4d, 0x4f, 0x44, 0x4f,
0x20, 0x43, 0x41, 0x20, 0x4c, 0x69, 0x6d, 0x69,
0x74, 0x65, 0x64, 0x31, 0x27, 0x30, 0x25, 0x06,
0x03, 0x55, 0x04, 0x03, 0x13, 0x1e, 0x43, 0x4f,
0x4d, 0x4f, 0x44, 0x4f, 0x20, 0x43, 0x65, 0x72,
0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f,
0x72, 0x69, 0x74, 0x79,
},
.der_len = 132,
},
{
.compat =
"C=HU, "
"L=Budapest, "
"O=Microsec Ltd., "
"2.5.4.97=VATHU-23584497, "
"CN=e-Szigno Root CA 2017",
.oneline =
"/C=HU"
"/L=Budapest"
"/O=Microsec Ltd."
"/2.5.4.97=VATHU-23584497"
"/CN=e-Szigno Root CA 2017",
.der = {
0x30, 0x71, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
0x55, 0x04, 0x06, 0x13, 0x02, 0x48, 0x55, 0x31,
0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07,
0x0c, 0x08, 0x42, 0x75, 0x64, 0x61, 0x70, 0x65,
0x73, 0x74, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03,
0x55, 0x04, 0x0a, 0x0c, 0x0d, 0x4d, 0x69, 0x63,
0x72, 0x6f, 0x73, 0x65, 0x63, 0x20, 0x4c, 0x74,
0x64, 0x2e, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03,
0x55, 0x04, 0x61, 0x0c, 0x0e, 0x56, 0x41, 0x54,
0x48, 0x55, 0x2d, 0x32, 0x33, 0x35, 0x38, 0x34,
0x34, 0x39, 0x37, 0x31, 0x1e, 0x30, 0x1c, 0x06,
0x03, 0x55, 0x04, 0x03, 0x0c, 0x15, 0x65, 0x2d,
0x53, 0x7a, 0x69, 0x67, 0x6e, 0x6f, 0x20, 0x52,
0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x32,
0x30, 0x31, 0x37,
},
.der_len = 115,
},
{
.compat =
"C=ES, "
"O=FNMT-RCM, "
"OU=Ceres, "
"2.5.4.97=VATES-Q2826004J, "
"CN=AC RAIZ FNMT-RCM SERVIDORES SEGUROS",
.oneline =
"/C=ES"
"/O=FNMT-RCM"
"/OU=Ceres"
"/2.5.4.97=VATES-Q2826004J"
"/CN=AC RAIZ FNMT-RCM SERVIDORES SEGUROS",
.der = {
0x30, 0x78, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
0x55, 0x04, 0x06, 0x13, 0x02, 0x45, 0x53, 0x31,
0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0a,
0x0c, 0x08, 0x46, 0x4e, 0x4d, 0x54, 0x2d, 0x52,
0x43, 0x4d, 0x31, 0x0e, 0x30, 0x0c, 0x06, 0x03,
0x55, 0x04, 0x0b, 0x0c, 0x05, 0x43, 0x65, 0x72,
0x65, 0x73, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03,
0x55, 0x04, 0x61, 0x0c, 0x0f, 0x56, 0x41, 0x54,
0x45, 0x53, 0x2d, 0x51, 0x32, 0x38, 0x32, 0x36,
0x30, 0x30, 0x34, 0x4a, 0x31, 0x2c, 0x30, 0x2a,
0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x23, 0x41,
0x43, 0x20, 0x52, 0x41, 0x49, 0x5a, 0x20, 0x46,
0x4e, 0x4d, 0x54, 0x2d, 0x52, 0x43, 0x4d, 0x20,
0x53, 0x45, 0x52, 0x56, 0x49, 0x44, 0x4f, 0x52,
0x45, 0x53, 0x20, 0x53, 0x45, 0x47, 0x55, 0x52,
0x4f, 0x53
},
.der_len = 122,
},
};
#define N_X509_NAME_COMPAT \
(sizeof(x509_name_legacy_test) / sizeof(x509_name_legacy_test[0]))
static int
x509_name_compat_testcase(const struct x509_name_legacy *test)
{
const uint8_t *p;
X509_NAME *name = NULL;
unsigned char *der = NULL;
int der_len = 0;
BIO *bio = NULL;
char *got;
int got_len;
char *buf = NULL;
int failed = 1;
p = test->der;
if ((name = d2i_X509_NAME(NULL, &p, test->der_len)) == NULL)
errx(1, "d2i_X509_NAME");
if ((der_len = i2d_X509_NAME(name, &der)) <= 0) {
fprintf(stderr, "FAIL: %s: i2d_X509_NAME", __func__);
der_len = 0;
goto err;
}
if (test->der_len != (size_t)der_len) {
fprintf(stderr, "FAIL: %s: der len: want %zu, got %d\n",
__func__, test->der_len, der_len);
goto err;
}
if (memcmp(test->der, der, test->der_len) != 0) {
fprintf(stderr, "FAIL: %s: DER mismatch\n", __func__);
goto err;
}
if ((bio = BIO_new(BIO_s_mem())) == NULL)
errx(1, "BIO_new");
if (!X509_NAME_print_ex(bio, name, 0, XN_FLAG_COMPAT)) {
fprintf(stderr, "FAIL: %s: X509_NAME_print_ex", __func__);
goto err;
}
if ((got_len = BIO_get_mem_data(bio, &got)) < 0)
errx(1, "BIO_get_mem_data");
if (strcmp(test->compat, got) != 0) {
fprintf(stderr, "FAIL: %s compat:\nwant: \"%s\",\ngot: \"%s\"\n",
__func__, test->compat, got);
goto err;
}
if ((buf = X509_NAME_oneline(name, NULL, 0)) == NULL)
errx(1, "X509_NAME_oneline");
if (strcmp(test->oneline, buf) != 0) {
fprintf(stderr, "FAIL: %s oneline:\nwant: \"%s\",\ngot: \"%s\"\n",
__func__, test->compat, got);
goto err;
}
failed = 0;
err:
BIO_free(bio);
free(buf);
X509_NAME_free(name);
freezero(der, der_len);
return failed;
}
static int
x509_name_compat_test(void)
{
size_t i;
int failed = 0;
for (i = 0; i < N_X509_NAME_COMPAT; i++)
failed |= x509_name_compat_testcase(&x509_name_legacy_test[i]);
return failed;
}
static const struct x509_name_entry_test {
const char *field;
const char *value;
int loc;
int set;
const char *expected_str;
const int expected_set[4];
const int expected_count;
} entry_tests[] = {
{
.field = "ST",
.value = "BaWue",
.loc = -1,
.set = 0,
.expected_str = "ST=BaWue",
.expected_set = { 0 },
.expected_count = 1,
},
{
.field = "O",
.value = "KIT",
.loc = -1,
.set = 0,
.expected_str = "ST=BaWue, O=KIT",
.expected_set = { 0, 1 },
.expected_count = 2,
},
{
.field = "L",
.value = "Karlsruhe",
.loc = 1,
.set = 0,
.expected_str = "ST=BaWue, L=Karlsruhe, O=KIT",
.expected_set = { 0, 1, 2 },
.expected_count = 3,
},
{
.field = "C",
.value = "DE",
.loc = 0,
.set = 1,
.expected_str = "C=DE + ST=BaWue, L=Karlsruhe, O=KIT",
.expected_set = { 0, 0, 1, 2 },
.expected_count = 4,
},
};
#define N_ENTRY_TESTS (sizeof(entry_tests) / sizeof(entry_tests[0]))
static int
verify_x509_name_output(X509_NAME *name, const struct x509_name_entry_test *tc)
{
BIO *bio;
char *got;
long got_len;
int loc, ret;
int failed = 1;
if ((bio = BIO_new(BIO_s_mem())) == NULL)
goto fail;
if ((ret = X509_NAME_print_ex(bio, name, 0, XN_FLAG_SEP_CPLUS_SPC)) == -1)
goto fail;
if ((got_len = BIO_get_mem_data(bio, &got)) < 0)
goto fail;
if (ret != got_len || strlen(tc->expected_str) != (size_t)ret)
goto fail;
if (strncmp(tc->expected_str, got, got_len) != 0)
goto fail;
if (X509_NAME_entry_count(name) != tc->expected_count)
goto fail;
for (loc = 0; loc < X509_NAME_entry_count(name); loc++) {
X509_NAME_ENTRY *e = X509_NAME_get_entry(name, loc);
if (e == NULL || X509_NAME_ENTRY_set(e) != tc->expected_set[loc])
goto fail;
}
failed = 0;
fail:
BIO_free(bio);
return failed;
}
static int
x509_name_add_entry_test(void)
{
X509_NAME *name;
int failed = 1;
if ((name = X509_NAME_new()) == NULL)
goto done;
for (size_t i = 0; i < N_ENTRY_TESTS; i++) {
const struct x509_name_entry_test *t = &entry_tests[i];
if (!X509_NAME_add_entry_by_txt(name, t->field, MBSTRING_ASC,
(const unsigned char *)t->value, -1, t->loc, t->set))
goto done;
if (verify_x509_name_output(name, t))
goto done;
}
failed = 0;
done:
X509_NAME_free(name);
return failed;
}
int
main(void)
{
int failed = 0;
failed |= x509_name_compat_test();
failed |= x509_name_add_entry_test();
return failed;
}