コード例 #1
0
ファイル: confread.c プロジェクト: codeboten/strongswan
static void load_also_cas(starter_ca_t *ca, also_t *also, starter_config_t *cfg)
{
	while (also != NULL)
	{
		kw_list_t *kw = find_also_ca(also->name, ca, cfg);

		if (kw == NULL)
		{
			DBG1(DBG_APP, "  ca '%s' cannot include '%s'", ca->name,
				 also->name);
		}
		else
		{
			DBG2(DBG_APP, "ca '%s' includes '%s'", ca->name, also->name);
			/* only load if no error occurred in the first round */
			if (cfg->err == 0)
			load_ca(ca, kw, cfg);
		}
		also = also->next;
	}
}
コード例 #2
0
ファイル: tls_init.c プロジェクト: abh-gitcs1989/opensips
/*
 * initialize tls virtual domains
 */
int
init_tls_domains(struct tls_domain *d)
{
	struct tls_domain *dom;

	dom = d;
	while (d) {
		if (d->name.len) {
			LM_INFO("Processing TLS domain '%.*s'\n",
				d->name.len, ZSW(d->name.s));
		} else {
			LM_INFO("Processing TLS domain [%s:%d]\n",
				ip_addr2a(&d->addr), d->port);
		}

		/*
		* set method
		*/
		if (d->method == TLS_METHOD_UNSPEC) {
			LM_DBG("no method for tls[%s:%d], using default\n",
				ip_addr2a(&d->addr), d->port);
			d->method = tls_method;
		}

		/*
		* create context
		*/
		d->ctx = SSL_CTX_new(ssl_methods[d->method - 1]);
		if (d->ctx == NULL) {
			LM_ERR("cannot create ssl context for "
				"tls[%s:%d]\n", ip_addr2a(&d->addr), d->port);
			return -1;
		}
		if (init_ssl_ctx_behavior( d ) < 0)
			return -1;

		/*
		* load certificate
		*/
		if (!d->cert_file) {
			LM_NOTICE("no certificate for tls[%s:%d] defined, using default"
					"'%s'\n", ip_addr2a(&d->addr), d->port,	tls_cert_file);
			d->cert_file = tls_cert_file;
		}
		if (load_certificate(d->ctx, d->cert_file) < 0)
			return -1;

		/*
		* load ca
		*/
		if (!d->ca_file) {
			LM_NOTICE("no CA for tls[%s:%d] defined, "
				"using default '%s'\n", ip_addr2a(&d->addr), d->port,
				tls_ca_file);
			d->ca_file = tls_ca_file;
		}
		if (d->ca_file && load_ca(d->ctx, d->ca_file) < 0)
			return -1;

		/*
		* load ca from directory
		*/
		if (!d->ca_directory) {

			LM_NOTICE("no CA for tls[%s:%d] defined, "
				"using default '%s'\n", ip_addr2a(&d->addr), d->port,
				 tls_ca_dir);
			d->ca_directory = tls_ca_dir;
		}

		if (d->ca_directory && load_ca_dir(d->ctx, d->ca_directory) < 0)
			return -1;

		d = d->next;
	}

	/*
	* load all private keys as the last step (may prompt for password)
	*/
	d = dom;
	while (d) {
		if (!d->pkey_file) {
			LM_NOTICE("no private key for tls[%s:%d] defined, using default"
					"'%s'\n", ip_addr2a(&d->addr), d->port, tls_pkey_file);
			d->pkey_file = tls_pkey_file;
		}
		if (load_private_key(d->ctx, d->pkey_file) < 0)
			return -1;
		d = d->next;
	}
	return 0;
}
コード例 #3
0
static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **options)
{
    TLSContext *c = h->priv_data;
    TLSShared *s = &c->tls_shared;
    int ret;

    if ((ret = ff_tls_open_underlying(s, h, uri, options)) < 0)
        goto fail;

    c->ssl_context = SSLCreateContext(NULL, s->listen ? kSSLServerSide : kSSLClientSide, kSSLStreamType);
    if (!c->ssl_context) {
        av_log(h, AV_LOG_ERROR, "Unable to create SSL context\n");
        ret = AVERROR(ENOMEM);
        goto fail;
    }
    if (s->ca_file) {
        if ((ret = load_ca(h)) < 0)
            goto fail;
    }
    if (s->ca_file || !s->verify)
        CHECK_ERROR(SSLSetSessionOption, c->ssl_context, kSSLSessionOptionBreakOnServerAuth, true);
    if (s->cert_file)
        if ((ret = load_cert(h)) < 0)
            goto fail;
    CHECK_ERROR(SSLSetPeerDomainName, c->ssl_context, s->host, strlen(s->host));
    CHECK_ERROR(SSLSetIOFuncs, c->ssl_context, tls_read_cb, tls_write_cb);
    CHECK_ERROR(SSLSetConnection, c->ssl_context, h);
    while (1) {
        OSStatus status = SSLHandshake(c->ssl_context);
        if (status == errSSLServerAuthCompleted) {
            SecTrustRef peerTrust;
            SecTrustResultType trustResult;
            if (!s->verify)
                continue;

            if (SSLCopyPeerTrust(c->ssl_context, &peerTrust) != noErr) {
                ret = AVERROR(ENOMEM);
                goto fail;
            }

            if (SecTrustSetAnchorCertificates(peerTrust, c->ca_array) != noErr) {
                ret = AVERROR_UNKNOWN;
                goto fail;
            }

            if (SecTrustEvaluate(peerTrust, &trustResult) != noErr) {
                ret = AVERROR_UNKNOWN;
                goto fail;
            }

            if (trustResult == kSecTrustResultProceed ||
                trustResult == kSecTrustResultUnspecified) {
                // certificate is trusted
                status = errSSLWouldBlock; // so we call SSLHandshake again
            } else if (trustResult == kSecTrustResultRecoverableTrustFailure) {
                // not trusted, for some reason other than being expired
                status = errSSLXCertChainInvalid;
            } else {
                // cannot use this certificate (fatal)
                status = errSSLBadCert;
            }

            if (peerTrust)
                CFRelease(peerTrust);
        }
        if (status == noErr)
            break;

        av_log(h, AV_LOG_ERROR, "Unable to negotiate TLS/SSL session: %i\n", (int)status);
        ret = AVERROR(EIO);
        goto fail;
    }

    return 0;
fail:
    tls_close(h);
    return ret;
}
コード例 #4
0
ファイル: tls_init.c プロジェクト: BackupTheBerlios/ser
/*
 * called once from main.c (main process) 
 */
int
init_tls(void)
{
	struct tls_domain *d;
	DBG("init_tls: Entered\n");
#if OPENSSL_VERSION_NUMBER < 0x00907000L
	LOG(L_ERR, "WARNING! You are using an old version of OpenSSL (< 0.9.7). Upgrade!\n");
#endif
	LOG(L_ALERT, "WARNING! TLS is considered as an EXPERIMENTAL module\n" );	
	/*
		* this has to be called before any function calling CRYPTO_malloc,
		* CRYPTO_malloc will set allow_customize in openssl to 0 
		*/
	if (!CRYPTO_set_mem_functions(ser_malloc, ser_realloc, ser_free)) {
		LOG(L_ERR,
			"init_tls: Unable to set the memory allocation functions\n");
		return -1;
	}
	
	SSL_library_init();
	SSL_load_error_strings();
	init_ssl_methods();

	/*
	 * initialize default context first 
	 */
	default_ctx = SSL_CTX_new(ssl_methods[tls_method - 1]);
	if (default_ctx == NULL) {
		LOG(L_ERR, "init_tls: Cannot create default ssl context\n");
		return -1;
	}
	init_ssl_ctx_behavior( default_ctx );
	if (load_certificate(default_ctx, tls_cert_file) < 0)
		return -1;
	if (tls_ca_file && load_ca(default_ctx, tls_ca_file) < 0)
		return -1;
	if (load_private_key(default_ctx, tls_pkey_file) < 0)
		return -1;

	/*
	 * now initialize tls virtual domains 
	 */
	d = tls_domains;
	while (d) {
		DBG("init_tls: Processing TLS domain [%s:%d]\n",
				ip_addr2a(&d->addr), d->port);
		/*
		* create context 
		*/
		if (d->method == TLS_METHOD_UNSPEC) {
			DBG("init_tls: No method for tls[%s:%d], using default\n",
			ip_addr2a(&d->addr), d->port);
			d->method = tls_method;
		}
	
		d->ctx = SSL_CTX_new(ssl_methods[d->method - 1]);
		if (d->ctx == NULL) {
			LOG(L_ERR,
				"init_tls: Cannot create ssl context for tls[%s:%d]\n",
				ip_addr2a(&d->addr), d->port);
			return -1;
		}
		init_ssl_ctx_behavior( d->ctx );
		/*
		* load certificate 
		*/
		if (!d->cert_file) {
			LOG(L_NOTICE,
				"init_tls: No certificate for tls[%s:%d] defined, using default '%s'\n",
				ip_addr2a(&d->addr), d->port, tls_cert_file);
			d->cert_file = tls_cert_file;
		}
		if (load_certificate(d->ctx, d->cert_file) < 0)
			return -1;
	
		/*
		* load ca 
		*/
		if (!d->ca_file) {
			LOG(L_NOTICE,
				"init_tls: No CA for tls[%s:%d] defined, using default '%s'\n",
				ip_addr2a(&d->addr), d->port, tls_ca_file);
			d->ca_file = tls_ca_file;
		}
		if (d->ca_file && load_ca(d->ctx, d->ca_file) < 0)
			return -1;
		d = d->next;
	}

	/*
		* load all private keys as the last step (may prompt for password) 
		*/
	d = tls_domains;
	while (d) {
		if (!d->pkey_file) {
			LOG(L_NOTICE,
				"init_tls: No private key for tls[%s:%d] defined, using default '%s'\n",
				ip_addr2a(&d->addr), d->port, tls_pkey_file);
			d->pkey_file = tls_pkey_file;
		}
		if (load_private_key(d->ctx, d->pkey_file) < 0)
			return -1;
		d = d->next;
	}
	/*
	 * we are all set 
	 */
	return 0;
}
コード例 #5
0
ファイル: confread.c プロジェクト: codeboten/strongswan
/*
 * load and parse an IPsec configuration file
 */
starter_config_t* confread_load(const char *file)
{
	starter_config_t *cfg = NULL;
	config_parsed_t  *cfgp;
	section_list_t   *sconn, *sca;
	starter_conn_t   *conn;
	starter_ca_t     *ca;

	u_int total_err;
	u_int visit	= 0;

	/* load IPSec configuration file  */
	cfgp = parser_load_conf(file);
	if (!cfgp)
	{
		return NULL;
	}
	cfg = malloc_thing(starter_config_t);

	/* set default values */
	default_values(cfg);

	/* load config setup section */
	load_setup(cfg, cfgp);

	/* in the first round parse also statements */
	cfg->parse_also = TRUE;

	/* find %default ca section */
	for (sca = cfgp->ca_first; sca; sca = sca->next)
	{
		if (streq(sca->name, "%default"))
		{
			DBG2(DBG_APP, "Loading ca %%default");
			load_ca(&cfg->ca_default, sca->kw, cfg);
		}
	}

	/* parameters defined in ca %default sections can be overloads */
	cfg->ca_default.seen = SEEN_NONE;

	/* load other ca sections */
	for (sca = cfgp->ca_first; sca; sca = sca->next)
	{
		u_int previous_err;

		/* skip %default ca section */
		if (streq(sca->name, "%default"))
			continue;

		DBG2(DBG_APP, "Loading ca '%s'", sca->name);
		ca = malloc_thing(starter_ca_t);

		ca_default(sca->name, ca, &cfg->ca_default);
		ca->kw =  sca->kw;
		ca->next = NULL;

		previous_err = cfg->err;
		load_ca(ca, ca->kw, cfg);
		if (cfg->err > previous_err)
		{
			/* errors occurred - free the ca */
			confread_free_ca(ca);
			cfg->non_fatal_err += cfg->err - previous_err;
			cfg->err = previous_err;
		}
		else
		{
			/* success - insert the ca into the chained list */
			if (cfg->ca_last)
				cfg->ca_last->next = ca;
			cfg->ca_last = ca;
			if (!cfg->ca_first)
				cfg->ca_first = ca;
		}
	}

	for (ca = cfg->ca_first; ca; ca = ca->next)
	{
		also_t *also = ca->also;

		while (also != NULL)
		{
			kw_list_t *kw = find_also_ca(also->name, cfg->ca_first, cfg);

			load_ca(ca, kw, cfg);
			also = also->next;
		}

		if (ca->startup != STARTUP_NO)
			ca->state = STATE_TO_ADD;
	}

	/* find %default conn sections */
	for (sconn = cfgp->conn_first; sconn; sconn = sconn->next)
	{
		if (streq(sconn->name, "%default"))
		{
			DBG2(DBG_APP, "Loading conn %%default");
			load_conn(&cfg->conn_default, sconn->kw, cfg);
		}
	}

	/* parameters defined in conn %default sections can be overloaded */
	cfg->conn_default.seen       = SEEN_NONE;
	cfg->conn_default.right.seen = SEEN_NONE;
	cfg->conn_default.left.seen  = SEEN_NONE;

	/* load other conn sections */
	for (sconn = cfgp->conn_first; sconn; sconn = sconn->next)
	{
		u_int previous_err;

		/* skip %default conn section */
		if (streq(sconn->name, "%default"))
			continue;

		DBG2(DBG_APP, "Loading conn '%s'", sconn->name);
		conn = malloc_thing(starter_conn_t);

		conn_default(sconn->name, conn, &cfg->conn_default);
		conn->kw =  sconn->kw;
		conn->next = NULL;

		previous_err = cfg->err;
		load_conn(conn, conn->kw, cfg);
		if (cfg->err > previous_err)
		{
			/* error occurred - free the conn */
			confread_free_conn(conn);
			cfg->non_fatal_err += cfg->err - previous_err;
			cfg->err = previous_err;
		}
		else
		{
			/* success - insert the conn into the chained list */
			if (cfg->conn_last)
				cfg->conn_last->next = conn;
			cfg->conn_last = conn;
			if (!cfg->conn_first)
				cfg->conn_first = conn;
		}
	}

	/* in the second round do not parse also statements */
	cfg->parse_also = FALSE;

	for (ca = cfg->ca_first; ca; ca = ca->next)
	{
		ca->visit = ++visit;
		load_also_cas(ca, ca->also, cfg);

		if (ca->startup != STARTUP_NO)
			ca->state = STATE_TO_ADD;
	}

	for (conn = cfg->conn_first; conn; conn = conn->next)
	{
		conn->visit = ++visit;
		load_also_conns(conn, conn->also, cfg);

		if (conn->startup != STARTUP_NO)
			conn->state = STATE_TO_ADD;
	}

	parser_free_conf(cfgp);

	total_err = cfg->err + cfg->non_fatal_err;
	if (total_err > 0)
	{
		DBG1(DBG_APP, "### %d parsing error%s (%d fatal) ###",
			 total_err, (total_err > 1)?"s":"", cfg->err);
	}

	return cfg;
}
コード例 #6
0
ファイル: 2cca.c プロジェクト: randunel/2cca
/*
 * Revoke one certificate at a time
 * No check performed to see if certificate already revoked.
 */
void revoke_cert(char * ca_name, char * name)
{
    char filename[FIELD_SZ+5];
    FILE * f ;
    X509_CRL * crl ;
    X509 * cert ;
    ASN1_INTEGER * r_serial ;
    ASN1_INTEGER * crlnum ;
    X509_REVOKED * rev ;
    ASN1_TIME * tm ;
    identity ca ;
    BIO * out ;
    BIGNUM * b_crlnum ;

    /* Find requested certificate by name */
    sprintf(filename, "%s.crt", name);
    if ((f=fopen(filename, "r"))==NULL) {
        fprintf(stderr, "Cannot find: %s\n", filename);
        return ; 
    }
    cert = PEM_read_X509(f, NULL, NULL, NULL);
    fclose(f);
    /* Get certificate serial number */
    r_serial = X509_get_serialNumber(cert);

    /* Find out if if was already revoked */

    /* Make a revoked object with that serial */
    rev = X509_REVOKED_new();
    X509_REVOKED_set_serialNumber(rev, r_serial);
    X509_free(cert);
    /* Set reason to unspecified */
    rev->reason = ASN1_ENUMERATED_get(CRL_REASON_UNSPECIFIED);

    /* Load or create new CRL */
    if ((crl = load_crl(ca_name))==NULL) {
        crl = X509_CRL_new();
        X509_CRL_set_version(crl, 1);
        /* Set CRL number */
        crlnum = ASN1_INTEGER_new();
        ASN1_INTEGER_set(crlnum, 1);
        X509_CRL_add1_ext_i2d(crl, NID_crl_number, crlnum, 0, 0);
        ASN1_INTEGER_free(crlnum);
    } else {
        crlnum = X509_CRL_get_ext_d2i(crl, NID_crl_number, 0, 0);
        b_crlnum = ASN1_INTEGER_to_BN(crlnum, NULL);
        BN_add_word(b_crlnum, 1);
        BN_to_ASN1_INTEGER(b_crlnum, crlnum);
        BN_free(b_crlnum);
        X509_CRL_add1_ext_i2d(crl, NID_crl_number, crlnum, 0, X509V3_ADD_REPLACE_EXISTING);
        ASN1_INTEGER_free(crlnum);
    }

    /* What time is it? */
    tm = ASN1_TIME_new();
    X509_gmtime_adj(tm, 0);
    X509_REVOKED_set_revocationDate(rev, tm);
    X509_CRL_set_lastUpdate(crl, tm);

    /* Set CRL next update to a year from now */
    X509_gmtime_adj(tm, 365*24*60*60);
    X509_CRL_set_nextUpdate(crl, tm);
    ASN1_TIME_free(tm);

    /* Add revoked to CRL */
    X509_CRL_add0_revoked(crl, rev);    
    X509_CRL_sort(crl);

    /* Load root key to sign CRL */
    if (load_ca(ca_name, &ca)!=0) {
        fprintf(stderr, "Cannot find CA key/crt\n");
        return ;
    }
    X509_CRL_set_issuer_name(crl, X509_get_subject_name(ca.cert));
    X509_free(ca.cert);

    /* Sign CRL */
    X509_CRL_sign(crl, ca.key, EVP_sha256());
    EVP_PKEY_free(ca.key);

    /* Dump CRL */
    sprintf(filename, "%s.crl", ca_name);
    if ((f = fopen(filename, "wb"))==NULL) {
        fprintf(stderr, "Cannot write %s: aborting\n", filename);
        X509_CRL_free(crl);
        return ;
    }
    out = BIO_new(BIO_s_file());
    BIO_set_fp(out, f, BIO_NOCLOSE);
    PEM_write_bio_X509_CRL(out, crl);
    BIO_free_all(out);
    fclose(f);
    X509_CRL_free(crl);
    return ;
}
コード例 #7
0
ファイル: 2cca.c プロジェクト: randunel/2cca
/*
 * Create identity
 */
int build_identity(void)
{
    EVP_PKEY * pkey ;
    RSA * rsa ;
    EC_KEY * ecc ;
    X509 * cert ;
    X509_NAME * name ;
    identity ca ;
    char filename[FIELD_SZ+5];
    FILE * pem ;

    /* Check before overwriting */
    sprintf(filename, "%s.crt", certinfo.cn);
    if (access(filename, F_OK)!=-1) {
        fprintf(stderr, "identity named %s already exists in this directory. Exiting now\n", filename);
        return -1 ;
    }
    sprintf(filename, "%s.key", certinfo.cn);
    if (access(filename, F_OK)!=-1) {
        fprintf(stderr, "identity named %s already exists in this directory. Exiting now\n", filename);
        return -1 ;
    }

    switch (certinfo.profile) {
        case PROFILE_ROOT_CA:
        strcpy(certinfo.ou, "Root");
        break;

        case PROFILE_SUB_CA:
        strcpy(certinfo.ou, "Sub");
        break;

        case PROFILE_SERVER:
        strcpy(certinfo.ou, "Server");
        break;
        
        case PROFILE_CLIENT:
        strcpy(certinfo.ou, "Client");
        break;

        case PROFILE_WWW:
        strcpy(certinfo.ou, "Server");
        break;

        default:
        fprintf(stderr, "Unknown profile: aborting\n");
        return -1 ;
    }

    if (certinfo.ec_name[0] && certinfo.profile!=PROFILE_CLIENT) {
        fprintf(stderr, "ECC keys are only supported for clients\n");
        return -1 ;
    }

    if (certinfo.profile != PROFILE_ROOT_CA) {
        /* Need to load signing CA */
        if (load_ca(certinfo.signing_ca, &ca)!=0) {
            fprintf(stderr, "Cannot find CA key or certificate\n");
            return -1 ;
        }
        /* Organization is the same as root */
        X509_NAME_get_text_by_NID(X509_get_subject_name(ca.cert),
                                  NID_organizationName,
                                  certinfo.o,
                                  FIELD_SZ);
    }

    /* Generate key pair */
    if (certinfo.ec_name[0]) {
        printf("Generating EC key [%s]\n", certinfo.ec_name);
        ecc = EC_KEY_new_by_curve_name(OBJ_txt2nid(certinfo.ec_name));
        if (!ecc) {
            fprintf(stderr, "Unknown curve: [%s]\n", certinfo.ec_name);
            return -1 ;
        }
        EC_KEY_set_asn1_flag(ecc, OPENSSL_EC_NAMED_CURVE);
        EC_KEY_generate_key(ecc);
        pkey = EVP_PKEY_new();
        EVP_PKEY_assign_EC_KEY(pkey, ecc);
    } else {
        printf("Generating RSA-%d key\n", certinfo.rsa_keysz);
        pkey = EVP_PKEY_new();
        rsa = RSA_generate_key(certinfo.rsa_keysz, RSA_F4, progress, 0);
        EVP_PKEY_assign_RSA(pkey, rsa);
    }

    /* Assign all certificate fields */
    cert = X509_new();
    X509_set_version(cert, 2);
    set_serial128(cert);
    X509_gmtime_adj(X509_get_notBefore(cert), 0);
    X509_gmtime_adj(X509_get_notAfter(cert), certinfo.days * 24*60*60);
    X509_set_pubkey(cert, pkey);

    name = X509_get_subject_name(cert);
    if (certinfo.c[0]) {
        X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, (unsigned char*)certinfo.c, -1, -1, 0);
    }
    X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, (unsigned char*)certinfo.o, -1, -1, 0);
    X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (unsigned char*)certinfo.cn, -1, -1, 0);
    X509_NAME_add_entry_by_txt(name, "OU", MBSTRING_ASC, (unsigned char*)certinfo.ou, -1, -1, 0);
    if (certinfo.l[0]) {
        X509_NAME_add_entry_by_txt(name, "L", MBSTRING_ASC, (unsigned char *)certinfo.l, -1, -1, 0);
    }
    if (certinfo.st[0]) {
        X509_NAME_add_entry_by_txt(name, "ST", MBSTRING_ASC, (unsigned char *)certinfo.st, -1, -1, 0);
    }

    /* Set extensions according to profile */
    switch (certinfo.profile) {
        case PROFILE_ROOT_CA:
        /* CA profiles can issue certs and sign CRLS */
        set_extension(cert, cert, NID_basic_constraints, "critical,CA:TRUE");
        set_extension(cert, cert, NID_key_usage, "critical,keyCertSign,cRLSign");
        set_extension(cert, cert, NID_subject_key_identifier, "hash");
        set_extension(cert, cert, NID_authority_key_identifier, "keyid:always");
        break ;

        case PROFILE_SUB_CA:
        /* CA profiles can issue certs and sign CRLS */
        set_extension(ca.cert, cert, NID_basic_constraints, "critical,CA:TRUE");
        set_extension(ca.cert, cert, NID_key_usage, "critical,keyCertSign,cRLSign");
        set_extension(ca.cert, cert, NID_subject_key_identifier, "hash");
        set_extension(ca.cert, cert, NID_authority_key_identifier, "keyid:always");
        break;

        case PROFILE_CLIENT:
        if (certinfo.san[0]) {
            set_extension(ca.cert, cert, NID_subject_alt_name, certinfo.san);
        }
        set_extension(ca.cert, cert, NID_basic_constraints, "CA:FALSE");
        set_extension(ca.cert, cert, NID_anyExtendedKeyUsage, "clientAuth");
        set_extension(ca.cert, cert, NID_key_usage, "digitalSignature");
        set_extension(ca.cert, cert, NID_subject_key_identifier, "hash");
        set_extension(ca.cert, cert, NID_authority_key_identifier, "issuer:always,keyid:always");
        break ;

        case PROFILE_SERVER:
        if (certinfo.san[0]) {
            set_extension(ca.cert, cert, NID_subject_alt_name, certinfo.san);
        }
        set_extension(ca.cert, cert, NID_basic_constraints, "CA:FALSE");
        set_extension(ca.cert, cert, NID_netscape_cert_type, "server");
        set_extension(ca.cert, cert, NID_anyExtendedKeyUsage, "serverAuth");
        set_extension(ca.cert, cert, NID_key_usage, "digitalSignature,keyEncipherment");
        set_extension(ca.cert, cert, NID_subject_key_identifier, "hash");
        set_extension(ca.cert, cert, NID_authority_key_identifier, "issuer:always,keyid:always");
        break ;

        case PROFILE_WWW:
        if (certinfo.san[0]) {
            set_extension(ca.cert, cert, NID_subject_alt_name, certinfo.san);
        }
        set_extension(ca.cert, cert, NID_basic_constraints, "CA:FALSE");
        set_extension(ca.cert, cert, NID_netscape_cert_type, "server");
        set_extension(ca.cert, cert, NID_anyExtendedKeyUsage, "serverAuth,clientAuth");
        set_extension(ca.cert, cert, NID_key_usage, "digitalSignature,keyEncipherment");
        set_extension(ca.cert, cert, NID_subject_key_identifier, "hash");
        set_extension(ca.cert, cert, NID_authority_key_identifier, "issuer:always,keyid:always");
        break;

        case PROFILE_UNKNOWN:
        default:
        break ;
    }
    /* Set issuer */
    if (certinfo.profile==PROFILE_ROOT_CA) {
        /* Self-signed */
        X509_set_issuer_name(cert, name);
        X509_sign(cert, pkey, EVP_sha256());
    } else {
        /* Signed by parent CA */
        X509_set_issuer_name(cert, X509_get_subject_name(ca.cert));
        X509_sign(cert, ca.key, EVP_sha256());
    }

    printf("Saving results to %s.[crt|key]\n", certinfo.cn);
    pem = fopen(filename, "wb");
    PEM_write_PrivateKey(pem, pkey, NULL, NULL, 0, NULL, NULL);
    fclose(pem);
    sprintf(filename, "%s.crt", certinfo.cn);
    pem = fopen(filename, "wb");
    PEM_write_X509(pem, cert);
    fclose(pem);
    X509_free(cert);
    EVP_PKEY_free(pkey);

    if (certinfo.profile!=PROFILE_ROOT_CA) {
        X509_free(ca.cert);
        EVP_PKEY_free(ca.key);
    }
    printf("done\n");

    return 0;
}