/*
*
* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 Yokogawa Electric Corporation,
* YDC Corporation, IPA (Information-technology Promotion Agency, Japan).
* All rights reserved.
*
* Redistribution and use of this software in source and binary forms, with
* or without modification, are permitted provided that the following
* conditions and disclaimer are agreed and accepted by the user:
*
* 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.
*
* 3. Neither the names of the copyrighters, the name of the project which
* is related to this software (hereinafter referred to as "project") nor
* the names of the contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* 4. No merchantable use may be permitted without prior written
* notification to the copyrighters. However, using this software for the
* purpose of testing or evaluating any products including merchantable
* products may be permitted without any notification to the copyrighters.
*
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHTERS, THE PROJECT AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING
* BUT NOT LIMITED THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHTERS, THE PROJECT OR CONTRIBUTORS 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.
*
* $TAHI: v6eval/bin/x509dec/x509dec.c,v 1.10 2005/05/30 10:17:31 akisada Exp $
*
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <libgen.h>
#include <errno.h>
#include <unistd.h>
#include <sys/queue.h>
#include <openssl/err.h>
#include <openssl/bn.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include "x509dec.h"
typedef unsigned char bool;
static const bool false = 0;
static const bool true = 1;
static const char *prog = NULL;
static const bool x509dec_main(const char *const);
static const bool x509dec_main_return(const bool, BIGNUM *);
static const bool x509dec_on_x509(const BIGNUM *const);
static const bool x509dec_on_x509_return(const bool, X509 *, unsigned char *);
static const bool x509dec_on_evp(const X509 *const);
static void x509dec_dump(const unsigned char *const, const int,
const unsigned char *const, const int, struct tailq *);
static const bool x509dec_on_evp_return(const bool,
unsigned char *, unsigned char *);
static unsigned char *const X509dec_get_pubkey(const X509 *const, int *);
static unsigned char *const
X509dec_get_pubkey_return(unsigned char *const pubkey,
unsigned char *, EVP_PKEY *);
static unsigned char *const X509dec_get_subject_name(const X509 *const, int *);
static const unsigned char *
const X509dec_get_subject_alt_name(const X509 *const, struct tailq *);
static void openssl_strerror(const char *const);
static void usage(void);
int
main(int argc, char **argv, char **envp)
{
const char *dertxt = NULL;
if(!(prog = basename(argv[0]))) {
fprintf(stderr, "err: basename: %s -- %s\n",
strerror(errno), argv[0]);
return(-1);
/* NOTREACHED */
}
{
int ch = 0;
while((ch = getopt(argc, argv, "d:")) != -1) {
switch (ch) {
case 'd':
dertxt = optarg;
break;
default:
usage();
/* NOTREACHED */
break;
}
}
argc -= optind;
argv += optind;
}
if(argc || !dertxt) {
usage();
/* NOTREACHED */
}
return(x509dec_main(dertxt)? 0: -1);
/* NOTREACHED */
}
static const bool
x509dec_main(const char *const dertxt)
{
BIGNUM *bignum = NULL;
ERR_load_crypto_strings();
if(!(bignum = BN_new())) {
openssl_strerror("BN_new");
return(x509dec_main_return(false, bignum));
}
if(!BN_hex2bn(&bignum, (const char *)dertxt)) {
openssl_strerror("BN_hex2bn");
return(x509dec_main_return(false, bignum));
}
if(!x509dec_on_x509(bignum)) {
return(x509dec_main_return(false, bignum));
}
return(x509dec_main_return(true, bignum));
}
static const bool
x509dec_main_return(const bool code, BIGNUM *bignum)
{
if(bignum) {
BN_free(bignum); bignum = 0;
}
return(code);
}
static const bool
x509dec_on_x509(const BIGNUM *const bignum)
{
int buflen = 0;
unsigned char *buf = NULL, *ptr = NULL;
X509 *x509 = NULL;
if(!(buflen = BN_num_bytes(bignum))) {
openssl_strerror("BN_num_bytes");
return(x509dec_on_x509_return(false, x509, buf));
}
if(!(buf = (unsigned char *)malloc(buflen))) {
fprintf(stderr, "err: malloc: %s\n", strerror(errno));
return(x509dec_on_x509_return(false, x509, buf));
}
if(BN_bn2bin(bignum, buf) != buflen) {
openssl_strerror("BN_bn2bin");
return(x509dec_on_x509_return(false, x509, buf));
}
ptr = buf;
if(!(x509 = d2i_X509(NULL, &ptr, buflen))) {
openssl_strerror("d2i_X509");
return(x509dec_on_x509_return(false, x509, buf));
}
if(!x509dec_on_evp(x509)) {
return(x509dec_on_x509_return(false, x509, buf));
}
return(x509dec_on_x509_return(true, x509, buf));
}
static const bool
x509dec_on_x509_return(const bool code, X509 *x509, unsigned char *buf)
{
if(x509) {
X509_free(x509); x509 = 0;
}
if(buf) {
free(buf); buf = 0;
}
return(code);
}
static const bool
x509dec_on_evp(const X509 *const x509)
{
unsigned char *pubkey = NULL;
int pubkeylen = 0;
unsigned char *subject_name = NULL;
int subject_namelen = 0;
struct tailq head = TAILQ_HEAD_INITIALIZER(head);
TAILQ_INIT(&head);
if(!((unsigned char *)pubkey =
X509dec_get_pubkey(x509, &pubkeylen))) {
return(x509dec_on_evp_return(false, pubkey, subject_name));
}
if(!((unsigned char *)subject_name =
X509dec_get_subject_name(x509, (int *)&subject_namelen))) {
return(x509dec_on_evp_return(false, pubkey, subject_name));
}
X509dec_get_subject_alt_name(x509, (struct tailq *)&head);
x509dec_dump(pubkey, pubkeylen,
subject_name, subject_namelen, (struct tailq *)&head);
return(x509dec_on_evp_return(true, pubkey, subject_name));
}
static void
x509dec_dump(const unsigned char *const pubkey, const int pubkeylen,
const unsigned char *const subject_name, const int subject_namelen,
struct tailq *head)
{
int d = 0;
int total = 0;
int extlen = 0;
struct name *name = NULL;
total = pubkeylen + subject_namelen;
TAILQ_FOREACH(name, head, names) {
extlen += name->name_len;
}
total += extlen;
printf("log:X509dec_Results (length:%d)\n", total);
printf("log:| SubjectName (length:%d)\n",
subject_namelen);
printf("log:| | data = ");
for(d = 0; d < subject_namelen; d ++) {
printf("%02x", subject_name[d]);
}
printf("\n");
printf("log:| PublicKey (length:%d)\n",
pubkeylen);
printf("log:| | data = ");
for(d = 0; d < pubkeylen; d ++) {
printf("%02x", pubkey[d]);
}
printf("\n");
if(extlen) {
printf("log:| Extensions (length:%d)\n",
extlen);
TAILQ_FOREACH(name, head, names) {
printf("log:| | SubjectAltName (length:%d)\n",
name->name_len);
printf("log:| | | Type = %d\n", name->name_type);
printf("log:| | | Data (length:%d)\n", name->name_len);
printf("log:| | | | data = ");
for(d = 0; d < name->name_len; d ++) {
printf("%02x", name->name_buf[d]);
}
printf("\n");
}
}
}
static const bool
x509dec_on_evp_return(const bool code,
unsigned char *pubkey, unsigned char *subject_name)
{
if(subject_name) {
free(subject_name); subject_name = NULL;
}
if(pubkey) {
free(pubkey); pubkey = NULL;
}
return(code);
}
static unsigned char *const
X509dec_get_pubkey(const X509 *const x509, int *buflen)
{
EVP_PKEY *evp = NULL;
unsigned char *buf = NULL, *ptr = NULL;
#if 0
int evp_pkey_type = 0;
const BIGNUM *bignum = NULL;
#endif
if(!(evp = X509_get_pubkey((X509 *)x509))) {
openssl_strerror("X509_get_pubkey");
return(X509dec_get_pubkey_return(NULL, buf, evp));
}
#if 0
evp_pkey_type = EVP_PKEY_type(evp->type);
switch(evp_pkey_type) {
case EVP_PKEY_RSA:
*buflen = BN_num_bytes(evp->pkey.rsa->n);
bignum = evp->pkey.rsa->n;
break;
case EVP_PKEY_DSA:
*buflen = BN_num_bytes(evp->pkey.dsa->pub_key);
bignum = evp->pkey.dsa->pub_key;
break;
default:
fprintf(stderr,
"err: EVP_PKEY_type: unknown type -- %d\n",
evp_pkey_type);
return(X509dec_get_pubkey_return(NULL, buf, evp));
break;
}
if(!(buf = (unsigned char *)malloc(*buflen))) {
fprintf(stderr, "err: malloc: %s\n", strerror(errno));
return(X509dec_get_pubkey_return(NULL, buf, evp));
}
if(BN_bn2bin(bignum, buf) != *buflen) {
openssl_strerror("BN_bn2bin");
return(X509dec_get_pubkey_return(NULL, buf, evp));
}
#else
if(!(*buflen = i2d_PublicKey(evp, NULL))) {
openssl_strerror("i2d_PublicKey");
return(X509dec_get_pubkey_return(NULL, buf, evp));
}
if(!(buf = (unsigned char *)malloc(*buflen))) {
fprintf(stderr, "err: malloc: %s\n", strerror(errno));
return(X509dec_get_pubkey_return(NULL, buf, evp));
}
ptr = buf;
if(i2d_PublicKey(evp, &ptr) != *buflen) {
openssl_strerror("i2d_PublicKey");
return(X509dec_get_pubkey_return(NULL, buf, evp));
}
#endif
return(X509dec_get_pubkey_return(buf, buf, evp));
}
static unsigned char *const
X509dec_get_pubkey_return(unsigned char *const pubkey,
unsigned char *buf, EVP_PKEY *evp)
{
if(!pubkey && buf) {
free(buf); buf = NULL;
}
if(evp) {
EVP_PKEY_free(evp); evp = NULL;
}
return(pubkey);
}
static unsigned char *const
X509dec_get_subject_name(const X509 *const x509, int *buflen)
{
X509_NAME *subject_name = NULL;
unsigned char *buf = NULL, *ptr = NULL;
if(!(subject_name = X509_get_subject_name((X509 *)x509))) {
openssl_strerror("X509_get_pubkey");
return(NULL);
}
if(!(*buflen = i2d_X509_NAME(subject_name, NULL))) {
openssl_strerror("i2d_X509_NAME");
return(NULL);
}
if(!(buf = (unsigned char *)malloc(*buflen))) {
fprintf(stderr, "err: malloc: %s\n", strerror(errno));
return(NULL);
}
ptr = buf;
if(i2d_X509_NAME(subject_name, &ptr) != *buflen) {
openssl_strerror("i2d_X509_NAME");
return(NULL);
}
return(buf);
}
static const unsigned char *const
X509dec_get_subject_alt_name(const X509 *const x509, struct tailq *head)
{
GENERAL_NAMES *extensions = NULL;
GENERAL_NAME *extension = NULL;
int subjAltName_pos = 0;
if(!(extensions = X509_get_ext_d2i((X509 *)x509,
NID_subject_alt_name, NULL, NULL))) {
openssl_strerror("X509_get_ext_d2i");
return(NULL);
}
for(subjAltName_pos = 0;
subjAltName_pos < sk_GENERAL_NAME_num(extensions);
subjAltName_pos ++) {
struct name *name = NULL;
extension = sk_GENERAL_NAME_value(extensions, subjAltName_pos);
if(!(name = (struct name *)malloc(sizeof(struct name)))) {
fprintf(stderr, "err: malloc: %s\n", strerror(errno));
return(NULL);
}
if(extension->d.ia5->data[extension->d.ia5->length] != '\0') {
fprintf(stderr,
"err: data is not terminated by '\\0'.\n");
return(NULL);
}
name->name_len = extension->d.ia5->length + 1;
if(!(name->name_buf =
(unsigned char *)malloc(name->name_len))) {
fprintf(stderr, "err: malloc: %s\n", strerror(errno));
return(NULL);
}
strlcpy(name->name_buf, extension->d.ia5->data, name->name_len);
name->name_type = extension->type;
TAILQ_INSERT_TAIL(head, name, names);
}
return(NULL);
}
static void
openssl_strerror(const char *const label)
{
unsigned long code = 0;
while((code = ERR_get_error())) {
fprintf(stderr, "err: %s: %s\n",
label, ERR_error_string(code, NULL));
}
return;
}
static void
usage(void)
{
fprintf(stderr, "err: usage: %s -d der\n", prog);
exit(-1);
/* NOTREACHED */
return;
}
syntax highlighted by Code2HTML, v. 0.9.1