1*49a6e16fSderaadt /* $OpenBSD: x509test.c,v 1.3 2021/12/13 16:56:49 deraadt Exp $ */
271ec8d3aScloder /* $EOM: x509test.c,v 1.9 2000/12/21 15:24:25 ho Exp $ */
371ec8d3aScloder
471ec8d3aScloder /*
571ec8d3aScloder * Copyright (c) 1998, 1999 Niels Provos. All rights reserved.
671ec8d3aScloder * Copyright (c) 1999, 2001 Niklas Hallqvist. All rights reserved.
771ec8d3aScloder * Copyright (c) 2001 H�kan Olsson. All rights reserved.
871ec8d3aScloder *
971ec8d3aScloder * Redistribution and use in source and binary forms, with or without
1071ec8d3aScloder * modification, are permitted provided that the following conditions
1171ec8d3aScloder * are met:
1271ec8d3aScloder * 1. Redistributions of source code must retain the above copyright
1371ec8d3aScloder * notice, this list of conditions and the following disclaimer.
1471ec8d3aScloder * 2. Redistributions in binary form must reproduce the above copyright
1571ec8d3aScloder * notice, this list of conditions and the following disclaimer in the
1671ec8d3aScloder * documentation and/or other materials provided with the distribution.
1771ec8d3aScloder *
1871ec8d3aScloder * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1971ec8d3aScloder * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2071ec8d3aScloder * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2171ec8d3aScloder * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2271ec8d3aScloder * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2371ec8d3aScloder * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2471ec8d3aScloder * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2571ec8d3aScloder * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2671ec8d3aScloder * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2771ec8d3aScloder * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2871ec8d3aScloder */
2971ec8d3aScloder
3071ec8d3aScloder /*
3171ec8d3aScloder * This code was written under funding by Ericsson Radio Systems.
3271ec8d3aScloder */
3371ec8d3aScloder
3471ec8d3aScloder /*
3571ec8d3aScloder * This program takes a certificate generated by ssleay and a key pair
3671ec8d3aScloder * from rsakeygen. It reads the IP address from certificate.txt and
3771ec8d3aScloder * includes this as subject alt name extension into the certifcate.
3871ec8d3aScloder * The result gets written as new certificate that can be used by
3971ec8d3aScloder * isakmpd.
4071ec8d3aScloder */
4171ec8d3aScloder
4271ec8d3aScloder #include <sys/types.h>
4371ec8d3aScloder #include <sys/mman.h>
4471ec8d3aScloder #include <sys/stat.h>
4571ec8d3aScloder #include <ctype.h>
4671ec8d3aScloder #include <fcntl.h>
4771ec8d3aScloder #include <stdio.h>
4871ec8d3aScloder #include <stdlib.h>
4971ec8d3aScloder #include <string.h>
5071ec8d3aScloder #include <unistd.h>
5171ec8d3aScloder
5271ec8d3aScloder #include <sys/socket.h>
5371ec8d3aScloder #include <netinet/in.h>
5471ec8d3aScloder #include <arpa/inet.h>
5571ec8d3aScloder
5671ec8d3aScloder #include "conf.h"
5771ec8d3aScloder #include "ipsec_num.h"
5871ec8d3aScloder #include "isakmp_fld.h"
5971ec8d3aScloder #include "libcrypto.h"
6071ec8d3aScloder #include "log.h"
6171ec8d3aScloder #include "math_mp.h"
6271ec8d3aScloder #include "x509.h"
6371ec8d3aScloder
6471ec8d3aScloder static int x509_check_subjectaltname (u_char *, u_int, X509 *);
6571ec8d3aScloder
6671ec8d3aScloder u_int32_t file_sz;
6771ec8d3aScloder
6871ec8d3aScloder #if 0
6971ec8d3aScloder /* XXX Currently unused. */
7071ec8d3aScloder static u_int8_t *
7171ec8d3aScloder open_file (char *name)
7271ec8d3aScloder {
7371ec8d3aScloder int fd;
7471ec8d3aScloder struct stat st;
7571ec8d3aScloder u_int8_t *addr;
7671ec8d3aScloder
7771ec8d3aScloder if (stat (name, &st) == -1)
7871ec8d3aScloder log_fatal ("stat (\"%s\", &st)", name);
7971ec8d3aScloder file_sz = st.st_size;
8071ec8d3aScloder fd = open (name, O_RDONLY);
8171ec8d3aScloder if (fd == -1)
8271ec8d3aScloder log_fatal ("open (\"%s\", O_RDONLY)", name);
8371ec8d3aScloder addr = mmap (0, file_sz, PROT_READ | PROT_WRITE, MAP_FILE | MAP_PRIVATE,
8471ec8d3aScloder fd, 0);
8571ec8d3aScloder if (addr == MAP_FAILED)
8671ec8d3aScloder log_fatal ("mmap (0, %d, PROT_READ | PROT_WRITE, MAP_FILE | MAP_PRIVATE,"
8771ec8d3aScloder "%d, 0)", file_sz, fd);
8871ec8d3aScloder close (fd);
8971ec8d3aScloder
9071ec8d3aScloder return addr;
9171ec8d3aScloder }
9271ec8d3aScloder #endif
9371ec8d3aScloder
9471ec8d3aScloder /*
9571ec8d3aScloder * Check that a certificate has a subjectAltName and that it matches our ID.
9671ec8d3aScloder */
9771ec8d3aScloder static int
x509_check_subjectaltname(u_char * id,u_int id_len,X509 * scert)9871ec8d3aScloder x509_check_subjectaltname (u_char *id, u_int id_len, X509 *scert)
9971ec8d3aScloder {
10071ec8d3aScloder u_int8_t *altname;
10171ec8d3aScloder u_int32_t altlen;
10271ec8d3aScloder int type, idtype, ret;
10371ec8d3aScloder
10471ec8d3aScloder type = x509_cert_subjectaltname (scert, &altname, &altlen);
10571ec8d3aScloder if (!type)
10671ec8d3aScloder {
10771ec8d3aScloder log_print ("x509_check_subjectaltname: can't access subjectAltName");
10871ec8d3aScloder return 0;
10971ec8d3aScloder }
11071ec8d3aScloder
11171ec8d3aScloder /*
11271ec8d3aScloder * Now that we have the X509 certicate in native form, get the
11371ec8d3aScloder * subjectAltName extension and verify that it matches our ID.
11471ec8d3aScloder */
11571ec8d3aScloder
11671ec8d3aScloder /* XXX Get type of ID. */
11771ec8d3aScloder idtype = id[0];
11871ec8d3aScloder id += ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ;
11971ec8d3aScloder id_len -= ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ;
12071ec8d3aScloder
12171ec8d3aScloder ret = 0;
12271ec8d3aScloder switch (idtype)
12371ec8d3aScloder {
12471ec8d3aScloder case IPSEC_ID_IPV4_ADDR:
12571ec8d3aScloder if (type == X509v3_IP_ADDR)
12671ec8d3aScloder ret = 1;
12771ec8d3aScloder break;
12871ec8d3aScloder case IPSEC_ID_FQDN:
12971ec8d3aScloder if (type == X509v3_DNS_NAME)
13071ec8d3aScloder ret = 1;
13171ec8d3aScloder break;
13271ec8d3aScloder case IPSEC_ID_USER_FQDN:
13371ec8d3aScloder if (type == X509v3_RFC_NAME)
13471ec8d3aScloder ret = 1;
13571ec8d3aScloder break;
13671ec8d3aScloder default:
13771ec8d3aScloder ret = 0;
13871ec8d3aScloder break;
13971ec8d3aScloder }
14071ec8d3aScloder
14171ec8d3aScloder if (!ret)
14271ec8d3aScloder {
14371ec8d3aScloder LOG_DBG ((LOG_CRYPTO, 50,
14471ec8d3aScloder "x509_check_subjectaltname: "
14571ec8d3aScloder "our ID type (%d) does not match X509 cert ID type (%d)",
14671ec8d3aScloder idtype, type));
14771ec8d3aScloder return 0;
14871ec8d3aScloder }
14971ec8d3aScloder
15071ec8d3aScloder if (altlen != id_len || memcmp (altname, id, id_len) != 0)
15171ec8d3aScloder {
15271ec8d3aScloder LOG_DBG ((LOG_CRYPTO, 50,
15371ec8d3aScloder "x509_check_subjectaltname: "
15471ec8d3aScloder "our ID does not match X509 cert ID"));
15571ec8d3aScloder return 0;
15671ec8d3aScloder }
15771ec8d3aScloder
15871ec8d3aScloder return 1;
15971ec8d3aScloder }
16071ec8d3aScloder
16171ec8d3aScloder int
main(int argc,char * argv[])16271ec8d3aScloder main (int argc, char *argv[])
16371ec8d3aScloder {
16471ec8d3aScloder RSA *pub_key, *priv_key;
16571ec8d3aScloder X509 *cert;
16671ec8d3aScloder BIO *certfile, *keyfile;
16771ec8d3aScloder EVP_PKEY *pkey_pub;
16871ec8d3aScloder u_char ipaddr[6];
16971ec8d3aScloder struct in_addr saddr;
17071ec8d3aScloder char enc[256], dec[256];
17171ec8d3aScloder u_int8_t idpayload[8];
17271ec8d3aScloder int err, len;
17371ec8d3aScloder
17471ec8d3aScloder if (argc < 3 || argc > 4)
17571ec8d3aScloder {
17671ec8d3aScloder fprintf (stderr, "usage: x509test private-key certificate ip-address\n");
17771ec8d3aScloder exit (1);
17871ec8d3aScloder }
17971ec8d3aScloder
18071ec8d3aScloder /*
18171ec8d3aScloder * X509_verify will fail, as will all other functions that call
18271ec8d3aScloder * EVP_get_digest_byname.
18371ec8d3aScloder */
18471ec8d3aScloder
18571ec8d3aScloder libcrypto_init ();
18671ec8d3aScloder
18771ec8d3aScloder printf ("Reading private key %s\n", argv[1]);
18871ec8d3aScloder keyfile = BIO_new (BIO_s_file ());
18971ec8d3aScloder if (BIO_read_filename (keyfile, argv[1]) == -1)
19071ec8d3aScloder {
19171ec8d3aScloder perror ("read");
19271ec8d3aScloder exit (1);
19371ec8d3aScloder }
19471ec8d3aScloder #if SSLEAY_VERSION_NUMBER >= 0x00904100L
19571ec8d3aScloder priv_key = PEM_read_bio_RSAPrivateKey (keyfile, NULL, NULL, NULL);
19671ec8d3aScloder #else
19771ec8d3aScloder priv_key = PEM_read_bio_RSAPrivateKey (keyfile, NULL, NULL);
19871ec8d3aScloder #endif
19971ec8d3aScloder BIO_free (keyfile);
20071ec8d3aScloder if (priv_key == NULL)
20171ec8d3aScloder {
20271ec8d3aScloder printf("PEM_read_bio_RSAPrivateKey () failed\n");
20371ec8d3aScloder exit (1);
20471ec8d3aScloder }
20571ec8d3aScloder
20671ec8d3aScloder /* Use a certificate created by ssleay. */
20771ec8d3aScloder printf ("Reading ssleay created certificate %s\n", argv[2]);
20871ec8d3aScloder certfile = BIO_new (BIO_s_file ());
20971ec8d3aScloder if (BIO_read_filename (certfile, argv[2]) == -1)
21071ec8d3aScloder {
21171ec8d3aScloder perror ("read");
21271ec8d3aScloder exit (1);
21371ec8d3aScloder }
21471ec8d3aScloder #if SSLEAY_VERSION_NUMBER >= 0x00904100L
21571ec8d3aScloder cert = PEM_read_bio_X509 (certfile, NULL, NULL, NULL);
21671ec8d3aScloder #else
21771ec8d3aScloder cert = PEM_read_bio_X509 (certfile, NULL, NULL);
21871ec8d3aScloder #endif
21971ec8d3aScloder BIO_free (certfile);
22071ec8d3aScloder if (cert == NULL)
22171ec8d3aScloder {
22271ec8d3aScloder printf("PEM_read_bio_X509 () failed\n");
22371ec8d3aScloder exit (1);
22471ec8d3aScloder }
22571ec8d3aScloder
22671ec8d3aScloder pkey_pub = X509_get_pubkey (cert);
22771ec8d3aScloder /* XXX Violation of the interface? */
22871ec8d3aScloder pub_key = pkey_pub->pkey.rsa;
22971ec8d3aScloder if (pub_key == NULL)
23071ec8d3aScloder {
23171ec8d3aScloder exit (1);
23271ec8d3aScloder }
23371ec8d3aScloder
23471ec8d3aScloder printf ("Testing RSA keys: ");
23571ec8d3aScloder
23671ec8d3aScloder err = 0;
23771ec8d3aScloder strlcpy (dec, "Eine kleine Testmeldung", 256);
23871ec8d3aScloder if ((len = RSA_private_encrypt (strlen (dec), dec, enc, priv_key,
23971ec8d3aScloder RSA_PKCS1_PADDING)) == -1)
24071ec8d3aScloder
24171ec8d3aScloder printf ("SIGN FAILED ");
24271ec8d3aScloder else
24371ec8d3aScloder err = RSA_public_decrypt (len, enc, dec, pub_key, RSA_PKCS1_PADDING);
24471ec8d3aScloder
24571ec8d3aScloder if (err == -1 || strcmp (dec, "Eine kleine Testmeldung"))
24671ec8d3aScloder printf ("SIGN/VERIFY FAILED");
24771ec8d3aScloder else
24871ec8d3aScloder printf ("OKAY");
24971ec8d3aScloder printf ("\n");
25071ec8d3aScloder
25171ec8d3aScloder
25271ec8d3aScloder printf ("Validate SIGNED: ");
25371ec8d3aScloder err = X509_verify (cert, pkey_pub);
25471ec8d3aScloder printf ("X509 verify: %d ", err);
25571ec8d3aScloder if (err == -1)
25671ec8d3aScloder printf ("FAILED ");
25771ec8d3aScloder else
25871ec8d3aScloder printf ("OKAY ");
25971ec8d3aScloder printf ("\n");
26071ec8d3aScloder
26171ec8d3aScloder if (argc == 4)
26271ec8d3aScloder {
26371ec8d3aScloder printf ("Verifying extension: ");
26471ec8d3aScloder if (inet_aton (argv[3], &saddr) == 0)
26571ec8d3aScloder {
26671ec8d3aScloder printf ("inet_aton () failed\n");
26771ec8d3aScloder exit (1);
26871ec8d3aScloder }
26971ec8d3aScloder
27071ec8d3aScloder saddr.s_addr = htonl (saddr.s_addr);
27171ec8d3aScloder ipaddr[0] = 0x87;
27271ec8d3aScloder ipaddr[1] = 0x04;
27371ec8d3aScloder ipaddr[2] = saddr.s_addr >> 24;
27471ec8d3aScloder ipaddr[3] = (saddr.s_addr >> 16) & 0xff;
27571ec8d3aScloder ipaddr[4] = (saddr.s_addr >> 8) & 0xff;
27671ec8d3aScloder ipaddr[5] = saddr.s_addr & 0xff;
27771ec8d3aScloder bzero (idpayload, sizeof idpayload);
27871ec8d3aScloder idpayload[0] = IPSEC_ID_IPV4_ADDR;
27971ec8d3aScloder bcopy (ipaddr + 2, idpayload + 4, 4);
28071ec8d3aScloder
28171ec8d3aScloder if (!x509_check_subjectaltname (idpayload, sizeof idpayload, cert))
28271ec8d3aScloder printf("FAILED ");
28371ec8d3aScloder else
28471ec8d3aScloder printf("OKAY ");
28571ec8d3aScloder printf ("\n");
28671ec8d3aScloder }
28771ec8d3aScloder
28871ec8d3aScloder return 1;
28971ec8d3aScloder }
290