/* $OpenBSD: x509test.c,v 1.22 2003/06/03 14:39:51 ho Exp $ */ /* $EOM: x509test.c,v 1.9 2000/12/21 15:24:25 ho Exp $ */ /* * Copyright (c) 1998, 1999 Niels Provos. All rights reserved. * Copyright (c) 1999, 2001 Niklas Hallqvist. All rights reserved. * Copyright (c) 2001 Håkan Olsson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * This code was written under funding by Ericsson Radio Systems. */ /* * This program takes a certificate generated by ssleay and a key pair * from rsakeygen. It reads the IP address from certificate.txt and * includes this as subject alt name extension into the certifcate. * The result gets written as new certificate that can be used by * isakmpd. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "conf.h" #include "ipsec_num.h" #include "isakmp_fld.h" #include "libcrypto.h" #include "log.h" #include "math_mp.h" #include "x509.h" static int x509_check_subjectaltname (u_char *, u_int, X509 *); u_int32_t file_sz; #if 0 /* XXX Currently unused. */ static u_int8_t * open_file (char *name) { int fd; struct stat st; u_int8_t *addr; if (stat (name, &st) == -1) log_fatal ("stat (\"%s\", &st)", name); file_sz = st.st_size; fd = open (name, O_RDONLY); if (fd == -1) log_fatal ("open (\"%s\", O_RDONLY)", name); addr = mmap (0, file_sz, PROT_READ | PROT_WRITE, MAP_FILE | MAP_PRIVATE, fd, 0); if (addr == MAP_FAILED) log_fatal ("mmap (0, %d, PROT_READ | PROT_WRITE, MAP_FILE | MAP_PRIVATE," "%d, 0)", file_sz, fd); close (fd); return addr; } #endif /* * Check that a certificate has a subjectAltName and that it matches our ID. */ static int x509_check_subjectaltname (u_char *id, u_int id_len, X509 *scert) { u_int8_t *altname; u_int32_t altlen; int type, idtype, ret; type = x509_cert_subjectaltname (scert, &altname, &altlen); if (!type) { log_print ("x509_check_subjectaltname: can't access subjectAltName"); return 0; } /* * Now that we have the X509 certicate in native form, get the * subjectAltName extension and verify that it matches our ID. */ /* XXX Get type of ID. */ idtype = id[0]; id += ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ; id_len -= ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ; ret = 0; switch (idtype) { case IPSEC_ID_IPV4_ADDR: if (type == X509v3_IP_ADDR) ret = 1; break; case IPSEC_ID_FQDN: if (type == X509v3_DNS_NAME) ret = 1; break; case IPSEC_ID_USER_FQDN: if (type == X509v3_RFC_NAME) ret = 1; break; default: ret = 0; break; } if (!ret) { LOG_DBG ((LOG_CRYPTO, 50, "x509_check_subjectaltname: " "our ID type (%d) does not match X509 cert ID type (%d)", idtype, type)); return 0; } if (altlen != id_len || memcmp (altname, id, id_len) != 0) { LOG_DBG ((LOG_CRYPTO, 50, "x509_check_subjectaltname: " "our ID does not match X509 cert ID")); return 0; } return 1; } int main (int argc, char *argv[]) { RSA *pub_key, *priv_key; X509 *cert; BIO *certfile, *keyfile; EVP_PKEY *pkey_pub; u_char ipaddr[6]; struct in_addr saddr; char enc[256], dec[256]; u_int8_t idpayload[8]; int err, len; if (argc < 3 || argc > 4) { fprintf (stderr, "usage: x509test private-key certificate ip-address\n"); exit (1); } /* * X509_verify will fail, as will all other functions that call * EVP_get_digest_byname. */ libcrypto_init (); printf ("Reading private key %s\n", argv[1]); keyfile = BIO_new (BIO_s_file ()); if (BIO_read_filename (keyfile, argv[1]) == -1) { perror ("read"); exit (1); } #if SSLEAY_VERSION_NUMBER >= 0x00904100L priv_key = PEM_read_bio_RSAPrivateKey (keyfile, NULL, NULL, NULL); #else priv_key = PEM_read_bio_RSAPrivateKey (keyfile, NULL, NULL); #endif BIO_free (keyfile); if (priv_key == NULL) { printf("PEM_read_bio_RSAPrivateKey () failed\n"); exit (1); } /* Use a certificate created by ssleay. */ printf ("Reading ssleay created certificate %s\n", argv[2]); certfile = BIO_new (BIO_s_file ()); if (BIO_read_filename (certfile, argv[2]) == -1) { perror ("read"); exit (1); } #if SSLEAY_VERSION_NUMBER >= 0x00904100L cert = PEM_read_bio_X509 (certfile, NULL, NULL, NULL); #else cert = PEM_read_bio_X509 (certfile, NULL, NULL); #endif BIO_free (certfile); if (cert == NULL) { printf("PEM_read_bio_X509 () failed\n"); exit (1); } pkey_pub = X509_get_pubkey (cert); /* XXX Violation of the interface? */ pub_key = pkey_pub->pkey.rsa; if (pub_key == NULL) { exit (1); } printf ("Testing RSA keys: "); err = 0; strlcpy (dec, "Eine kleine Testmeldung", 256); if ((len = RSA_private_encrypt (strlen (dec), dec, enc, priv_key, RSA_PKCS1_PADDING)) == -1) printf ("SIGN FAILED "); else err = RSA_public_decrypt (len, enc, dec, pub_key, RSA_PKCS1_PADDING); if (err == -1 || strcmp (dec, "Eine kleine Testmeldung")) printf ("SIGN/VERIFY FAILED"); else printf ("OKAY"); printf ("\n"); printf ("Validate SIGNED: "); err = X509_verify (cert, pkey_pub); printf ("X509 verify: %d ", err); if (err == -1) printf ("FAILED "); else printf ("OKAY "); printf ("\n"); if (argc == 4) { printf ("Verifying extension: "); if (inet_aton (argv[3], &saddr) == 0) { printf ("inet_aton () failed\n"); exit (1); } saddr.s_addr = htonl (saddr.s_addr); ipaddr[0] = 0x87; ipaddr[1] = 0x04; ipaddr[2] = saddr.s_addr >> 24; ipaddr[3] = (saddr.s_addr >> 16) & 0xff; ipaddr[4] = (saddr.s_addr >> 8) & 0xff; ipaddr[5] = saddr.s_addr & 0xff; bzero (idpayload, sizeof idpayload); idpayload[0] = IPSEC_ID_IPV4_ADDR; bcopy (ipaddr + 2, idpayload + 4, 4); if (!x509_check_subjectaltname (idpayload, sizeof idpayload, cert)) printf("FAILED "); else printf("OKAY "); printf ("\n"); } return 1; }