1*da668aa1SThomas Huth /* 2*da668aa1SThomas Huth * Copyright (C) 2015 Red Hat, Inc. 3*da668aa1SThomas Huth * 4*da668aa1SThomas Huth * This library is free software; you can redistribute it and/or 5*da668aa1SThomas Huth * modify it under the terms of the GNU Lesser General Public 6*da668aa1SThomas Huth * License as published by the Free Software Foundation; either 7*da668aa1SThomas Huth * version 2.1 of the License, or (at your option) any later version. 8*da668aa1SThomas Huth * 9*da668aa1SThomas Huth * This library is distributed in the hope that it will be useful, 10*da668aa1SThomas Huth * but WITHOUT ANY WARRANTY; without even the implied warranty of 11*da668aa1SThomas Huth * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12*da668aa1SThomas Huth * Lesser General Public License for more details. 13*da668aa1SThomas Huth * 14*da668aa1SThomas Huth * You should have received a copy of the GNU Lesser General Public 15*da668aa1SThomas Huth * License along with this library. If not, see 16*da668aa1SThomas Huth * <http://www.gnu.org/licenses/>. 17*da668aa1SThomas Huth * 18*da668aa1SThomas Huth * Author: Daniel P. Berrange <berrange@redhat.com> 19*da668aa1SThomas Huth */ 20*da668aa1SThomas Huth 21*da668aa1SThomas Huth #include "qemu/osdep.h" 22*da668aa1SThomas Huth 23*da668aa1SThomas Huth #include "crypto-tls-x509-helpers.h" 24*da668aa1SThomas Huth #include "crypto/init.h" 25*da668aa1SThomas Huth #include "qemu/sockets.h" 26*da668aa1SThomas Huth 27*da668aa1SThomas Huth #ifdef QCRYPTO_HAVE_TLS_TEST_SUPPORT 28*da668aa1SThomas Huth 29*da668aa1SThomas Huth /* 30*da668aa1SThomas Huth * This stores some static data that is needed when 31*da668aa1SThomas Huth * encoding extensions in the x509 certs 32*da668aa1SThomas Huth */ 33*da668aa1SThomas Huth asn1_node pkix_asn1; 34*da668aa1SThomas Huth 35*da668aa1SThomas Huth /* 36*da668aa1SThomas Huth * To avoid consuming random entropy to generate keys, 37*da668aa1SThomas Huth * here's one we prepared earlier :-) 38*da668aa1SThomas Huth */ 39*da668aa1SThomas Huth gnutls_x509_privkey_t privkey; 40*da668aa1SThomas Huth # define PRIVATE_KEY \ 41*da668aa1SThomas Huth "-----BEGIN RSA PRIVATE KEY-----\n" \ 42*da668aa1SThomas Huth "MIIG5AIBAAKCAYEAyjWyLSNm5PZvYUKUcDWGqbLX10b2ood+YaFjWSnJrqx/q3qh\n" \ 43*da668aa1SThomas Huth "rVGBJglD25AJENJsmZF3zPP1oMhfIxsXu63Hdkb6Rdlc2RUoUP34x9VC1izH25mR\n" \ 44*da668aa1SThomas Huth "6c8DPDp1d6IraZ/llDMI1HsBFz0qGWtvOHgm815XG4PAr/N8rDsuqfv/cJ01KlnO\n" \ 45*da668aa1SThomas Huth "0OdO5QRXCJf9g/dYd41MPu7wOXk9FqjQlmRoP59HgtJ+zUpE4z+Keruw9cMT9VJj\n" \ 46*da668aa1SThomas Huth "0oT+pQ9ysenqeZ3gbT224T1khrEhT5kifhtFLNyDssRchUUWH0hiqoOO1vgb+850\n" \ 47*da668aa1SThomas Huth "W6/1VdxvuPam48py4diSPi1Vip8NITCOBaX9FIpVp4Ruw4rTPVMNMjq9Cpx/DwMP\n" \ 48*da668aa1SThomas Huth "9MbfXfnaVaZaMrmq67/zPhl0eVbUrecH2hQ3ZB9oIF4GkNskzlWF5+yPy6zqk304\n" \ 49*da668aa1SThomas Huth "AKaiFR6jRyh3YfHo2XFqV8x/hxdsIEXOtEUGhSIcpynsW+ckUCartzu7xbhXjd4b\n" \ 50*da668aa1SThomas Huth "kxJT89+riPFYij09AgMBAAECggGBAKyFkaZXXROeejrmHlV6JZGlp+fhgM38gkRz\n" \ 51*da668aa1SThomas Huth "+Jp7P7rLLAY3E7gXIPQ91WqAAmwazFNdvHPd9USfkCQYmnAi/VoZhrCPmlsQZRxt\n" \ 52*da668aa1SThomas Huth "A5QjjOnEvSPMa6SrXZxGWDCg6R8uMCb4P+FhrPWR1thnRDZOtRTQ+crc50p3mHgt\n" \ 53*da668aa1SThomas Huth "6ktXWIJRbqnag8zSfQqCYGtRmhe8sfsWT+Yl4El4+jjaAVU/B364u7+PLmaiphGp\n" \ 54*da668aa1SThomas Huth "BdJfTsTwEpgtGkPj+osDmhzXcZkfq3V+fz5JLkemsCiQKmn4VJRpg8c3ZmE8NPNt\n" \ 55*da668aa1SThomas Huth "gRtGWZ4W3WKDvhotT65WpQx4+6R8Duux/blNPBmH1Upmwd7kj7GYFBArbCjgd9PT\n" \ 56*da668aa1SThomas Huth "xgfCSUZpgOZHHkcgSB+022a8XncXna7WYYij28SLtwImFyu0nNtqECFQHH5u+k6C\n" \ 57*da668aa1SThomas Huth "LRYBSN+3t3At8dQuk01NVrJBndmjmXRfxpqUtTdeaNgVpdUYRY98s30G68NYGSra\n" \ 58*da668aa1SThomas Huth "aEvhhRSghkcLNetkobpY9pUgeqW/tQKBwQDZHHK9nDMt/zk1TxtILeUSitPXcv1/\n" \ 59*da668aa1SThomas Huth "8ufXqO0miHdH23XuXhIEA6Ef26RRVGDGgpjkveDJK/1w5feJ4H/ni4Vclil/cm38\n" \ 60*da668aa1SThomas Huth "OwRqjjd7ElHJX6JQbsxEx/gNTk5/QW1iAL9TXUalgepsSXYT6AJ0/CJv0jmJSJ36\n" \ 61*da668aa1SThomas Huth "YoKMOM8uqzb2KhN6i+RlJRi5iY53kUhWTJq5ArWvNhUzQNSYODI4bNxlsKSBL2Ik\n" \ 62*da668aa1SThomas Huth "LZ5QKHuaEjQet0IlPlfIb4PzMm8CHa/urOcCgcEA7m3zW/lL5bIFoKPjWig5Lbn1\n" \ 63*da668aa1SThomas Huth "aHfrG2ngqzWtgWtfZqMH8OkZc1Mdhhmvd46titjiLjeI+UP/uHXR0068PnrNngzl\n" \ 64*da668aa1SThomas Huth "tTgwlakzu+bWzqhBm1F+3/341st/FEk07r0P/3/PhezVjwfO8c8Exj7pLxH4wrH0\n" \ 65*da668aa1SThomas Huth "ROHgDbClmlJRu6OO78wk1+Vapf5DWa8YfA+q+fdvr7KvgGyytheKMT/b/dsqOq7y\n" \ 66*da668aa1SThomas Huth "qZPjmaJKWAvV3RWG8lWHFSdHx2IAHMHfGr17Y/w7AoHBALzwZeYebeekiVucGSjq\n" \ 67*da668aa1SThomas Huth "T8SgLhT7zCIx+JMUPjVfYzaUhP/Iu7Lkma6IzWm9nW6Drpy5pUpMzwUWDCLfzU9q\n" \ 68*da668aa1SThomas Huth "eseFIl337kEn9wLn+t5OpgAyCqYmlftxbqvdrrBN9uvnrJjWvqk/8wsDrw9JxAGc\n" \ 69*da668aa1SThomas Huth "fjeD4nBXUqvYWLXApoR9mZoGKedmoH9pFig4zlO9ig8YITnKYuQ0k6SD0b8agJHc\n" \ 70*da668aa1SThomas Huth "Ir0YSUDnRGgpjvFBGbeOCe+FGbohk/EpItJc3IAh5740lwKBwAdXd2DjokSmYKn7\n" \ 71*da668aa1SThomas Huth "oeqKxofz6+yVlLW5YuOiuX78sWlVp87xPolgi84vSEnkKM/Xsc8+goc6YstpRVa+\n" \ 72*da668aa1SThomas Huth "W+mImoA9YW1dF5HkLeWhTAf9AlgoAEIhbeIfTgBv6KNZSv7RDrDPBBxtXx/vAfSg\n" \ 73*da668aa1SThomas Huth "x0ldwk0scZsVYXLKd67yzfV7KdGUdaX4N/xYgfZm/9gCG3+q8NN2KxVHQ5F71BOE\n" \ 74*da668aa1SThomas Huth "JeABOaGo9WvnU+DNMIDZjHJMUWVw4MHz/a/UArDf/2CxaPVBNQKBwASg6j4ohSTk\n" \ 75*da668aa1SThomas Huth "J7aE6RQ3OBmmDDpixcoCJt9u9SjHVYMlbs5CEJGVSczk0SG3y8P1lOWNDSRnMksZ\n" \ 76*da668aa1SThomas Huth "xWnHdP/ogcuYMuvK7UACNAF0zNddtzOhzcpNmejFj+WCHYY/UmPr2/Kf6t7Cxk2K\n" \ 77*da668aa1SThomas Huth "3cZ4tqWsiTmBT8Bknmah7L5DrhS+ZBJliDeFAA8fZHdMH0Xjr4UBp9kF90EMTdW1\n" \ 78*da668aa1SThomas Huth "Xr5uz7ZrMsYpYQI7mmyqV9SSjUg4iBXwVSoag1iDJ1K8Qg/L7Semgg==\n" \ 79*da668aa1SThomas Huth "-----END RSA PRIVATE KEY-----\n" 80*da668aa1SThomas Huth 81*da668aa1SThomas Huth /* 82*da668aa1SThomas Huth * This loads the private key we defined earlier 83*da668aa1SThomas Huth */ 84*da668aa1SThomas Huth static gnutls_x509_privkey_t test_tls_load_key(void) 85*da668aa1SThomas Huth { 86*da668aa1SThomas Huth gnutls_x509_privkey_t key; 87*da668aa1SThomas Huth const gnutls_datum_t data = { (unsigned char *)PRIVATE_KEY, 88*da668aa1SThomas Huth strlen(PRIVATE_KEY) }; 89*da668aa1SThomas Huth int err; 90*da668aa1SThomas Huth 91*da668aa1SThomas Huth err = gnutls_x509_privkey_init(&key); 92*da668aa1SThomas Huth if (err < 0) { 93*da668aa1SThomas Huth g_critical("Failed to init key %s", gnutls_strerror(err)); 94*da668aa1SThomas Huth abort(); 95*da668aa1SThomas Huth } 96*da668aa1SThomas Huth 97*da668aa1SThomas Huth err = gnutls_x509_privkey_import(key, &data, 98*da668aa1SThomas Huth GNUTLS_X509_FMT_PEM); 99*da668aa1SThomas Huth if (err < 0) { 100*da668aa1SThomas Huth if (err != GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR && 101*da668aa1SThomas Huth err != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { 102*da668aa1SThomas Huth g_critical("Failed to import key %s", gnutls_strerror(err)); 103*da668aa1SThomas Huth abort(); 104*da668aa1SThomas Huth } 105*da668aa1SThomas Huth 106*da668aa1SThomas Huth err = gnutls_x509_privkey_import_pkcs8( 107*da668aa1SThomas Huth key, &data, GNUTLS_X509_FMT_PEM, NULL, 0); 108*da668aa1SThomas Huth if (err < 0) { 109*da668aa1SThomas Huth g_critical("Failed to import PKCS8 key %s", gnutls_strerror(err)); 110*da668aa1SThomas Huth abort(); 111*da668aa1SThomas Huth } 112*da668aa1SThomas Huth } 113*da668aa1SThomas Huth 114*da668aa1SThomas Huth return key; 115*da668aa1SThomas Huth } 116*da668aa1SThomas Huth 117*da668aa1SThomas Huth 118*da668aa1SThomas Huth void test_tls_init(const char *keyfile) 119*da668aa1SThomas Huth { 120*da668aa1SThomas Huth qcrypto_init(&error_abort); 121*da668aa1SThomas Huth 122*da668aa1SThomas Huth if (asn1_array2tree(pkix_asn1_tab, &pkix_asn1, NULL) != ASN1_SUCCESS) { 123*da668aa1SThomas Huth abort(); 124*da668aa1SThomas Huth } 125*da668aa1SThomas Huth 126*da668aa1SThomas Huth privkey = test_tls_load_key(); 127*da668aa1SThomas Huth if (!g_file_set_contents(keyfile, PRIVATE_KEY, -1, NULL)) { 128*da668aa1SThomas Huth abort(); 129*da668aa1SThomas Huth } 130*da668aa1SThomas Huth } 131*da668aa1SThomas Huth 132*da668aa1SThomas Huth 133*da668aa1SThomas Huth void test_tls_cleanup(const char *keyfile) 134*da668aa1SThomas Huth { 135*da668aa1SThomas Huth asn1_delete_structure(&pkix_asn1); 136*da668aa1SThomas Huth unlink(keyfile); 137*da668aa1SThomas Huth } 138*da668aa1SThomas Huth 139*da668aa1SThomas Huth /* 140*da668aa1SThomas Huth * Turns an ASN1 object into a DER encoded byte array 141*da668aa1SThomas Huth */ 142*da668aa1SThomas Huth static void test_tls_der_encode(asn1_node src, 143*da668aa1SThomas Huth const char *src_name, 144*da668aa1SThomas Huth gnutls_datum_t *res) 145*da668aa1SThomas Huth { 146*da668aa1SThomas Huth int size; 147*da668aa1SThomas Huth char *data = NULL; 148*da668aa1SThomas Huth 149*da668aa1SThomas Huth size = 0; 150*da668aa1SThomas Huth asn1_der_coding(src, src_name, NULL, &size, NULL); 151*da668aa1SThomas Huth 152*da668aa1SThomas Huth data = g_new0(char, size); 153*da668aa1SThomas Huth 154*da668aa1SThomas Huth asn1_der_coding(src, src_name, data, &size, NULL); 155*da668aa1SThomas Huth 156*da668aa1SThomas Huth res->data = (unsigned char *)data; 157*da668aa1SThomas Huth res->size = size; 158*da668aa1SThomas Huth } 159*da668aa1SThomas Huth 160*da668aa1SThomas Huth 161*da668aa1SThomas Huth static void 162*da668aa1SThomas Huth test_tls_get_ipaddr(const char *addrstr, 163*da668aa1SThomas Huth char **data, 164*da668aa1SThomas Huth int *datalen) 165*da668aa1SThomas Huth { 166*da668aa1SThomas Huth struct addrinfo *res; 167*da668aa1SThomas Huth struct addrinfo hints; 168*da668aa1SThomas Huth 169*da668aa1SThomas Huth memset(&hints, 0, sizeof(hints)); 170*da668aa1SThomas Huth hints.ai_flags = AI_NUMERICHOST; 171*da668aa1SThomas Huth g_assert(getaddrinfo(addrstr, NULL, &hints, &res) == 0); 172*da668aa1SThomas Huth 173*da668aa1SThomas Huth *datalen = res->ai_addrlen; 174*da668aa1SThomas Huth *data = g_new(char, *datalen); 175*da668aa1SThomas Huth memcpy(*data, res->ai_addr, *datalen); 176*da668aa1SThomas Huth freeaddrinfo(res); 177*da668aa1SThomas Huth } 178*da668aa1SThomas Huth 179*da668aa1SThomas Huth /* 180*da668aa1SThomas Huth * This is a fairly lame x509 certificate generator. 181*da668aa1SThomas Huth * 182*da668aa1SThomas Huth * Do not copy/use this code for generating real certificates 183*da668aa1SThomas Huth * since it leaves out many things that you would want in 184*da668aa1SThomas Huth * certificates for real world usage. 185*da668aa1SThomas Huth * 186*da668aa1SThomas Huth * This is good enough only for doing tests of the QEMU 187*da668aa1SThomas Huth * TLS certificate code 188*da668aa1SThomas Huth */ 189*da668aa1SThomas Huth void 190*da668aa1SThomas Huth test_tls_generate_cert(QCryptoTLSTestCertReq *req, 191*da668aa1SThomas Huth gnutls_x509_crt_t ca) 192*da668aa1SThomas Huth { 193*da668aa1SThomas Huth gnutls_x509_crt_t crt; 194*da668aa1SThomas Huth int err; 195*da668aa1SThomas Huth static char buffer[1024 * 1024]; 196*da668aa1SThomas Huth size_t size = sizeof(buffer); 197*da668aa1SThomas Huth char serial[5] = { 1, 2, 3, 4, 0 }; 198*da668aa1SThomas Huth gnutls_datum_t der; 199*da668aa1SThomas Huth time_t start = time(NULL) + (60 * 60 * req->start_offset); 200*da668aa1SThomas Huth time_t expire = time(NULL) + (60 * 60 * (req->expire_offset 201*da668aa1SThomas Huth ? req->expire_offset : 24)); 202*da668aa1SThomas Huth 203*da668aa1SThomas Huth /* 204*da668aa1SThomas Huth * Prepare our new certificate object 205*da668aa1SThomas Huth */ 206*da668aa1SThomas Huth err = gnutls_x509_crt_init(&crt); 207*da668aa1SThomas Huth if (err < 0) { 208*da668aa1SThomas Huth g_critical("Failed to initialize certificate %s", gnutls_strerror(err)); 209*da668aa1SThomas Huth abort(); 210*da668aa1SThomas Huth } 211*da668aa1SThomas Huth err = gnutls_x509_crt_set_key(crt, privkey); 212*da668aa1SThomas Huth if (err < 0) { 213*da668aa1SThomas Huth g_critical("Failed to set certificate key %s", gnutls_strerror(err)); 214*da668aa1SThomas Huth abort(); 215*da668aa1SThomas Huth } 216*da668aa1SThomas Huth 217*da668aa1SThomas Huth /* 218*da668aa1SThomas Huth * A v3 certificate is required in order to be able 219*da668aa1SThomas Huth * set any of the basic constraints, key purpose and 220*da668aa1SThomas Huth * key usage data 221*da668aa1SThomas Huth */ 222*da668aa1SThomas Huth gnutls_x509_crt_set_version(crt, 3); 223*da668aa1SThomas Huth 224*da668aa1SThomas Huth if (req->country) { 225*da668aa1SThomas Huth err = gnutls_x509_crt_set_dn_by_oid( 226*da668aa1SThomas Huth crt, GNUTLS_OID_X520_COUNTRY_NAME, 0, 227*da668aa1SThomas Huth req->country, strlen(req->country)); 228*da668aa1SThomas Huth if (err < 0) { 229*da668aa1SThomas Huth g_critical("Failed to set certificate country name %s", 230*da668aa1SThomas Huth gnutls_strerror(err)); 231*da668aa1SThomas Huth abort(); 232*da668aa1SThomas Huth } 233*da668aa1SThomas Huth } 234*da668aa1SThomas Huth if (req->cn) { 235*da668aa1SThomas Huth err = gnutls_x509_crt_set_dn_by_oid( 236*da668aa1SThomas Huth crt, GNUTLS_OID_X520_COMMON_NAME, 0, 237*da668aa1SThomas Huth req->cn, strlen(req->cn)); 238*da668aa1SThomas Huth if (err < 0) { 239*da668aa1SThomas Huth g_critical("Failed to set certificate common name %s", 240*da668aa1SThomas Huth gnutls_strerror(err)); 241*da668aa1SThomas Huth abort(); 242*da668aa1SThomas Huth } 243*da668aa1SThomas Huth } 244*da668aa1SThomas Huth 245*da668aa1SThomas Huth /* 246*da668aa1SThomas Huth * Setup the subject altnames, which are used 247*da668aa1SThomas Huth * for hostname checks in live sessions 248*da668aa1SThomas Huth */ 249*da668aa1SThomas Huth if (req->altname1) { 250*da668aa1SThomas Huth err = gnutls_x509_crt_set_subject_alt_name( 251*da668aa1SThomas Huth crt, GNUTLS_SAN_DNSNAME, 252*da668aa1SThomas Huth req->altname1, 253*da668aa1SThomas Huth strlen(req->altname1), 254*da668aa1SThomas Huth GNUTLS_FSAN_APPEND); 255*da668aa1SThomas Huth if (err < 0) { 256*da668aa1SThomas Huth g_critical("Failed to set certificate alt name %s", 257*da668aa1SThomas Huth gnutls_strerror(err)); 258*da668aa1SThomas Huth abort(); 259*da668aa1SThomas Huth } 260*da668aa1SThomas Huth } 261*da668aa1SThomas Huth if (req->altname2) { 262*da668aa1SThomas Huth err = gnutls_x509_crt_set_subject_alt_name( 263*da668aa1SThomas Huth crt, GNUTLS_SAN_DNSNAME, 264*da668aa1SThomas Huth req->altname2, 265*da668aa1SThomas Huth strlen(req->altname2), 266*da668aa1SThomas Huth GNUTLS_FSAN_APPEND); 267*da668aa1SThomas Huth if (err < 0) { 268*da668aa1SThomas Huth g_critical("Failed to set certificate %s alt name", 269*da668aa1SThomas Huth gnutls_strerror(err)); 270*da668aa1SThomas Huth abort(); 271*da668aa1SThomas Huth } 272*da668aa1SThomas Huth } 273*da668aa1SThomas Huth 274*da668aa1SThomas Huth /* 275*da668aa1SThomas Huth * IP address need to be put into the cert in their 276*da668aa1SThomas Huth * raw byte form, not strings, hence this is a little 277*da668aa1SThomas Huth * more complicated 278*da668aa1SThomas Huth */ 279*da668aa1SThomas Huth if (req->ipaddr1) { 280*da668aa1SThomas Huth char *data; 281*da668aa1SThomas Huth int len; 282*da668aa1SThomas Huth 283*da668aa1SThomas Huth test_tls_get_ipaddr(req->ipaddr1, &data, &len); 284*da668aa1SThomas Huth 285*da668aa1SThomas Huth err = gnutls_x509_crt_set_subject_alt_name( 286*da668aa1SThomas Huth crt, GNUTLS_SAN_IPADDRESS, 287*da668aa1SThomas Huth data, len, GNUTLS_FSAN_APPEND); 288*da668aa1SThomas Huth if (err < 0) { 289*da668aa1SThomas Huth g_critical("Failed to set certificate alt name %s", 290*da668aa1SThomas Huth gnutls_strerror(err)); 291*da668aa1SThomas Huth abort(); 292*da668aa1SThomas Huth } 293*da668aa1SThomas Huth g_free(data); 294*da668aa1SThomas Huth } 295*da668aa1SThomas Huth if (req->ipaddr2) { 296*da668aa1SThomas Huth char *data; 297*da668aa1SThomas Huth int len; 298*da668aa1SThomas Huth 299*da668aa1SThomas Huth test_tls_get_ipaddr(req->ipaddr2, &data, &len); 300*da668aa1SThomas Huth 301*da668aa1SThomas Huth err = gnutls_x509_crt_set_subject_alt_name( 302*da668aa1SThomas Huth crt, GNUTLS_SAN_IPADDRESS, 303*da668aa1SThomas Huth data, len, GNUTLS_FSAN_APPEND); 304*da668aa1SThomas Huth if (err < 0) { 305*da668aa1SThomas Huth g_critical("Failed to set certificate alt name %s", 306*da668aa1SThomas Huth gnutls_strerror(err)); 307*da668aa1SThomas Huth abort(); 308*da668aa1SThomas Huth } 309*da668aa1SThomas Huth g_free(data); 310*da668aa1SThomas Huth } 311*da668aa1SThomas Huth 312*da668aa1SThomas Huth 313*da668aa1SThomas Huth /* 314*da668aa1SThomas Huth * Basic constraints are used to decide if the cert 315*da668aa1SThomas Huth * is for a CA or not. We can't use the convenient 316*da668aa1SThomas Huth * gnutls API for setting this, since it hardcodes 317*da668aa1SThomas Huth * the 'critical' field which we want control over 318*da668aa1SThomas Huth */ 319*da668aa1SThomas Huth if (req->basicConstraintsEnable) { 320*da668aa1SThomas Huth asn1_node ext = NULL; 321*da668aa1SThomas Huth 322*da668aa1SThomas Huth asn1_create_element(pkix_asn1, "PKIX1.BasicConstraints", &ext); 323*da668aa1SThomas Huth asn1_write_value(ext, "cA", 324*da668aa1SThomas Huth req->basicConstraintsIsCA ? "TRUE" : "FALSE", 1); 325*da668aa1SThomas Huth asn1_write_value(ext, "pathLenConstraint", NULL, 0); 326*da668aa1SThomas Huth test_tls_der_encode(ext, "", &der); 327*da668aa1SThomas Huth err = gnutls_x509_crt_set_extension_by_oid( 328*da668aa1SThomas Huth crt, "2.5.29.19", 329*da668aa1SThomas Huth der.data, der.size, 330*da668aa1SThomas Huth req->basicConstraintsCritical); 331*da668aa1SThomas Huth if (err < 0) { 332*da668aa1SThomas Huth g_critical("Failed to set certificate basic constraints %s", 333*da668aa1SThomas Huth gnutls_strerror(err)); 334*da668aa1SThomas Huth g_free(der.data); 335*da668aa1SThomas Huth abort(); 336*da668aa1SThomas Huth } 337*da668aa1SThomas Huth asn1_delete_structure(&ext); 338*da668aa1SThomas Huth g_free(der.data); 339*da668aa1SThomas Huth } 340*da668aa1SThomas Huth 341*da668aa1SThomas Huth /* 342*da668aa1SThomas Huth * Next up the key usage extension. Again we can't 343*da668aa1SThomas Huth * use the gnutls API since it hardcodes the extension 344*da668aa1SThomas Huth * to be 'critical' 345*da668aa1SThomas Huth */ 346*da668aa1SThomas Huth if (req->keyUsageEnable) { 347*da668aa1SThomas Huth asn1_node ext = NULL; 348*da668aa1SThomas Huth char str[2]; 349*da668aa1SThomas Huth 350*da668aa1SThomas Huth str[0] = req->keyUsageValue & 0xff; 351*da668aa1SThomas Huth str[1] = (req->keyUsageValue >> 8) & 0xff; 352*da668aa1SThomas Huth 353*da668aa1SThomas Huth asn1_create_element(pkix_asn1, "PKIX1.KeyUsage", &ext); 354*da668aa1SThomas Huth asn1_write_value(ext, "", str, 9); 355*da668aa1SThomas Huth test_tls_der_encode(ext, "", &der); 356*da668aa1SThomas Huth err = gnutls_x509_crt_set_extension_by_oid( 357*da668aa1SThomas Huth crt, "2.5.29.15", 358*da668aa1SThomas Huth der.data, der.size, 359*da668aa1SThomas Huth req->keyUsageCritical); 360*da668aa1SThomas Huth if (err < 0) { 361*da668aa1SThomas Huth g_critical("Failed to set certificate key usage %s", 362*da668aa1SThomas Huth gnutls_strerror(err)); 363*da668aa1SThomas Huth g_free(der.data); 364*da668aa1SThomas Huth abort(); 365*da668aa1SThomas Huth } 366*da668aa1SThomas Huth asn1_delete_structure(&ext); 367*da668aa1SThomas Huth g_free(der.data); 368*da668aa1SThomas Huth } 369*da668aa1SThomas Huth 370*da668aa1SThomas Huth /* 371*da668aa1SThomas Huth * Finally the key purpose extension. This time 372*da668aa1SThomas Huth * gnutls has the opposite problem, always hardcoding 373*da668aa1SThomas Huth * it to be non-critical. So once again we have to 374*da668aa1SThomas Huth * set this the hard way building up ASN1 data ourselves 375*da668aa1SThomas Huth */ 376*da668aa1SThomas Huth if (req->keyPurposeEnable) { 377*da668aa1SThomas Huth asn1_node ext = NULL; 378*da668aa1SThomas Huth 379*da668aa1SThomas Huth asn1_create_element(pkix_asn1, "PKIX1.ExtKeyUsageSyntax", &ext); 380*da668aa1SThomas Huth if (req->keyPurposeOID1) { 381*da668aa1SThomas Huth asn1_write_value(ext, "", "NEW", 1); 382*da668aa1SThomas Huth asn1_write_value(ext, "?LAST", req->keyPurposeOID1, 1); 383*da668aa1SThomas Huth } 384*da668aa1SThomas Huth if (req->keyPurposeOID2) { 385*da668aa1SThomas Huth asn1_write_value(ext, "", "NEW", 1); 386*da668aa1SThomas Huth asn1_write_value(ext, "?LAST", req->keyPurposeOID2, 1); 387*da668aa1SThomas Huth } 388*da668aa1SThomas Huth test_tls_der_encode(ext, "", &der); 389*da668aa1SThomas Huth err = gnutls_x509_crt_set_extension_by_oid( 390*da668aa1SThomas Huth crt, "2.5.29.37", 391*da668aa1SThomas Huth der.data, der.size, 392*da668aa1SThomas Huth req->keyPurposeCritical); 393*da668aa1SThomas Huth if (err < 0) { 394*da668aa1SThomas Huth g_critical("Failed to set certificate key purpose %s", 395*da668aa1SThomas Huth gnutls_strerror(err)); 396*da668aa1SThomas Huth g_free(der.data); 397*da668aa1SThomas Huth abort(); 398*da668aa1SThomas Huth } 399*da668aa1SThomas Huth asn1_delete_structure(&ext); 400*da668aa1SThomas Huth g_free(der.data); 401*da668aa1SThomas Huth } 402*da668aa1SThomas Huth 403*da668aa1SThomas Huth /* 404*da668aa1SThomas Huth * Any old serial number will do, so lets pick 5 405*da668aa1SThomas Huth */ 406*da668aa1SThomas Huth err = gnutls_x509_crt_set_serial(crt, serial, 5); 407*da668aa1SThomas Huth if (err < 0) { 408*da668aa1SThomas Huth g_critical("Failed to set certificate serial %s", 409*da668aa1SThomas Huth gnutls_strerror(err)); 410*da668aa1SThomas Huth abort(); 411*da668aa1SThomas Huth } 412*da668aa1SThomas Huth 413*da668aa1SThomas Huth err = gnutls_x509_crt_set_activation_time(crt, start); 414*da668aa1SThomas Huth if (err < 0) { 415*da668aa1SThomas Huth g_critical("Failed to set certificate activation %s", 416*da668aa1SThomas Huth gnutls_strerror(err)); 417*da668aa1SThomas Huth abort(); 418*da668aa1SThomas Huth } 419*da668aa1SThomas Huth err = gnutls_x509_crt_set_expiration_time(crt, expire); 420*da668aa1SThomas Huth if (err < 0) { 421*da668aa1SThomas Huth g_critical("Failed to set certificate expiration %s", 422*da668aa1SThomas Huth gnutls_strerror(err)); 423*da668aa1SThomas Huth abort(); 424*da668aa1SThomas Huth } 425*da668aa1SThomas Huth 426*da668aa1SThomas Huth 427*da668aa1SThomas Huth /* 428*da668aa1SThomas Huth * If no 'ca' is set then we are self signing 429*da668aa1SThomas Huth * the cert. This is done for the root CA certs 430*da668aa1SThomas Huth */ 431*da668aa1SThomas Huth err = gnutls_x509_crt_sign2(crt, ca ? ca : crt, privkey, 432*da668aa1SThomas Huth GNUTLS_DIG_SHA256, 0); 433*da668aa1SThomas Huth if (err < 0) { 434*da668aa1SThomas Huth g_critical("Failed to sign certificate %s", 435*da668aa1SThomas Huth gnutls_strerror(err)); 436*da668aa1SThomas Huth abort(); 437*da668aa1SThomas Huth } 438*da668aa1SThomas Huth 439*da668aa1SThomas Huth /* 440*da668aa1SThomas Huth * Finally write the new cert out to disk 441*da668aa1SThomas Huth */ 442*da668aa1SThomas Huth err = gnutls_x509_crt_export( 443*da668aa1SThomas Huth crt, GNUTLS_X509_FMT_PEM, buffer, &size); 444*da668aa1SThomas Huth if (err < 0) { 445*da668aa1SThomas Huth g_critical("Failed to export certificate %s: %d", 446*da668aa1SThomas Huth gnutls_strerror(err), err); 447*da668aa1SThomas Huth abort(); 448*da668aa1SThomas Huth } 449*da668aa1SThomas Huth 450*da668aa1SThomas Huth if (!g_file_set_contents(req->filename, buffer, -1, NULL)) { 451*da668aa1SThomas Huth g_critical("Failed to write certificate %s", 452*da668aa1SThomas Huth req->filename); 453*da668aa1SThomas Huth abort(); 454*da668aa1SThomas Huth } 455*da668aa1SThomas Huth 456*da668aa1SThomas Huth req->crt = crt; 457*da668aa1SThomas Huth } 458*da668aa1SThomas Huth 459*da668aa1SThomas Huth 460*da668aa1SThomas Huth void test_tls_write_cert_chain(const char *filename, 461*da668aa1SThomas Huth gnutls_x509_crt_t *certs, 462*da668aa1SThomas Huth size_t ncerts) 463*da668aa1SThomas Huth { 464*da668aa1SThomas Huth size_t i; 465*da668aa1SThomas Huth size_t capacity = 1024, offset = 0; 466*da668aa1SThomas Huth char *buffer = g_new0(char, capacity); 467*da668aa1SThomas Huth int err; 468*da668aa1SThomas Huth 469*da668aa1SThomas Huth for (i = 0; i < ncerts; i++) { 470*da668aa1SThomas Huth size_t len = capacity - offset; 471*da668aa1SThomas Huth retry: 472*da668aa1SThomas Huth err = gnutls_x509_crt_export(certs[i], GNUTLS_X509_FMT_PEM, 473*da668aa1SThomas Huth buffer + offset, &len); 474*da668aa1SThomas Huth if (err < 0) { 475*da668aa1SThomas Huth if (err == GNUTLS_E_SHORT_MEMORY_BUFFER) { 476*da668aa1SThomas Huth buffer = g_renew(char, buffer, offset + len); 477*da668aa1SThomas Huth capacity = offset + len; 478*da668aa1SThomas Huth goto retry; 479*da668aa1SThomas Huth } 480*da668aa1SThomas Huth g_critical("Failed to export certificate chain %s: %d", 481*da668aa1SThomas Huth gnutls_strerror(err), err); 482*da668aa1SThomas Huth abort(); 483*da668aa1SThomas Huth } 484*da668aa1SThomas Huth offset += len; 485*da668aa1SThomas Huth } 486*da668aa1SThomas Huth 487*da668aa1SThomas Huth if (!g_file_set_contents(filename, buffer, offset, NULL)) { 488*da668aa1SThomas Huth abort(); 489*da668aa1SThomas Huth } 490*da668aa1SThomas Huth g_free(buffer); 491*da668aa1SThomas Huth } 492*da668aa1SThomas Huth 493*da668aa1SThomas Huth 494*da668aa1SThomas Huth void test_tls_discard_cert(QCryptoTLSTestCertReq *req) 495*da668aa1SThomas Huth { 496*da668aa1SThomas Huth if (!req->crt) { 497*da668aa1SThomas Huth return; 498*da668aa1SThomas Huth } 499*da668aa1SThomas Huth 500*da668aa1SThomas Huth gnutls_x509_crt_deinit(req->crt); 501*da668aa1SThomas Huth req->crt = NULL; 502*da668aa1SThomas Huth 503*da668aa1SThomas Huth if (getenv("QEMU_TEST_DEBUG_CERTS") == NULL) { 504*da668aa1SThomas Huth unlink(req->filename); 505*da668aa1SThomas Huth } 506*da668aa1SThomas Huth } 507*da668aa1SThomas Huth 508*da668aa1SThomas Huth #endif /* QCRYPTO_HAVE_TLS_TEST_SUPPORT */ 509