Esempio n. 1
0
static gboolean
x509_compare_pubkeys (PurpleCertificate *crt1, PurpleCertificate *crt2)
{
	gnutls_x509_crt_t crt_dat1, crt_dat2;
	unsigned char buffer1[64], buffer2[64];
	size_t size1, size2;
	size1 = size2 = sizeof(buffer1);

	g_return_val_if_fail(crt1 && crt2, FALSE);
	g_return_val_if_fail(crt1->scheme == &x509_gnutls, FALSE);
	g_return_val_if_fail(crt2->scheme == &x509_gnutls, FALSE);

	crt_dat1 = X509_GET_GNUTLS_DATA(crt1);

	if (gnutls_x509_crt_get_key_id(crt_dat1, KEYID_FLAG, buffer1, &size1) != 0) {
		return FALSE;
	}

	crt_dat2 = X509_GET_GNUTLS_DATA(crt2);

	if (gnutls_x509_crt_get_key_id(crt_dat2, KEYID_FLAG, buffer2, &size2) != 0) {
		return FALSE;
	}

	if (size1 != size2) {
		return FALSE;
	}

	return memcmp(buffer1, buffer2, size1) == 0;
}
/*!
  Adds the authority key identifier extension to the certificate. The key
  is extracted the specified certificate which must be the one later used
  to sign the certificate.
 */
bool CertificateBuilder::addAuthorityKeyIdentifier(const QSslCertificate &qcacert)
{
    gnutls_x509_crt_t cacrt = qsslcert_to_crt(qcacert, &d->errnumber);
    if (GNUTLS_E_SUCCESS != d->errnumber)
        return false;

    QByteArray ba(128, 0); // Normally 20 bytes (SHA1)
    size_t size = ba.size();

    // Try using the subject keyid
    d->errnumber = gnutls_x509_crt_get_subject_key_id(cacrt, reinterpret_cast<unsigned char *>(ba.data()), &size, NULL);

    // Or fallback to creating it
    if (GNUTLS_E_SUCCESS != d->errnumber) {
        d->errnumber = gnutls_x509_crt_get_key_id(cacrt, 0, reinterpret_cast<unsigned char *>(ba.data()), &size);

        if (GNUTLS_E_SUCCESS != d->errnumber) {
            gnutls_x509_crt_deinit(cacrt);
            return false;
        }
    }

    gnutls_x509_crt_deinit(cacrt);
    d->errnumber = gnutls_x509_crt_set_authority_key_id(d->crt, reinterpret_cast<const unsigned char *>(ba.constData()), size);

    return GNUTLS_E_SUCCESS == d->errnumber;
}
Esempio n. 3
0
InfoHash
Certificate::getId() const
{
    if (not cert)
        return {};
    InfoHash id;
    size_t sz = id.size();
    if (gnutls_x509_crt_get_key_id(cert, 0, id.data(), &sz) != GNUTLS_E_SUCCESS || sz != id.size())
        throw CryptoException("Can't get certificate public key ID.");
    return id;
}
Esempio n. 4
0
static gnutls_x509_crt generate_certificate(requiem_client_profile_t *cp, gnutls_x509_privkey key, int expire)
{
        int ret;
        char buf[1024];
        gnutls_x509_crt crt;
        uint64_t analyzerid;
        size_t size = sizeof(buf);

        ret = gnutls_x509_crt_init(&crt);
        if ( ret < 0 ) {
                fprintf(stderr, "error creating x509 certificate: %s.\n", gnutls_strerror(ret));
                return NULL;
        }

        if ( ! expire )
                expire = 0x7fffffff;
        else
                expire = time(NULL) + expire * 24 * 60 * 60;

        gnutls_x509_crt_set_version(crt, 3);
        gnutls_x509_crt_set_ca_status(crt, 0);
        gnutls_x509_crt_set_activation_time(crt, time(NULL));
        gnutls_x509_crt_set_expiration_time(crt, expire);

        analyzerid = requiem_client_profile_get_analyzerid(cp);

        ret = snprintf(buf, sizeof(buf), "%" REQUIEM_PRIu64, analyzerid);
        ret = gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_DN_QUALIFIER, 0, buf, ret);
        if ( ret < 0 ) {
                fprintf(stderr, "error setting common name: %s.\n", gnutls_strerror(ret));
                return NULL;
        }

        gnutls_x509_crt_set_serial(crt, &analyzerid, sizeof(analyzerid));

        if ( ! key )
                return crt;

        gnutls_x509_crt_set_key(crt, key);

        ret = gnutls_x509_crt_get_key_id(crt, 0, (unsigned char *) buf, &size);
        if ( ret == 0 ) {

                ret = gnutls_x509_crt_set_subject_key_id(crt, buf, size);
                if ( ret < 0 ) {
                        gnutls_x509_crt_deinit(crt);
                        fprintf(stderr, "error setting subject key ID: %s\n", gnutls_strerror(ret));
                        return NULL;
                }
        }

        return crt;
}
/*!
  Adds the subject key identifier extension to the certificate. The key
  is extracted automatically from the certificate being created.
 */
bool CertificateBuilder::addSubjectKeyIdentifier()
{
    QByteArray ba(128, 0); // Normally 20 bytes (SHA1)
    size_t size = ba.size();

    d->errnumber = gnutls_x509_crt_get_key_id(d->crt, 0, reinterpret_cast<unsigned char *>(ba.data()), &size);
    if (GNUTLS_E_SUCCESS != d->errnumber)
        return false;

    d->errnumber = gnutls_x509_crt_set_subject_key_id (d->crt, ba.constData(), size);
    return GNUTLS_E_SUCCESS == d->errnumber;
}
Esempio n. 6
0
static gnutls_x509_crt generate_signed_certificate(requiem_client_profile_t *cp,
                                                   uint64_t analyzerid,
                                                   gnutls_x509_crt ca_crt,
                                                   gnutls_x509_privkey ca_key,
                                                   gnutls_x509_crq crq)
{
        int ret;
        gnutls_x509_crt crt;
        unsigned char buf[65535];
        size_t size = sizeof(buf);

        crt = generate_certificate(cp, NULL, generated_certificate_lifetime);
        if ( ! crt )
                return NULL;

        ret = gnutls_x509_crt_set_crq(crt, crq);
        if ( ret < 0 ) {
                fprintf(stderr, "error associating certificate with CRQ: %s.\n", gnutls_strerror(ret));
                goto err;
        }

        ret = gnutls_x509_crt_set_serial(crt, &analyzerid, sizeof(analyzerid));
        if ( ret < 0 ) {
                fprintf(stderr, "error setting certificate serial: %s.\n", gnutls_strerror(ret));
                goto err;
        }

        ret = gnutls_x509_crt_get_key_id(ca_crt, 0, buf, &size);
        if ( ret < 0 ) {
                fprintf(stderr, "error getting CA key ID: %s.\n", gnutls_strerror(ret));
                goto err;
        }

        ret = gnutls_x509_crt_set_authority_key_id(crt, buf, size);
        if ( ret < 0 ) {
                fprintf(stderr, "error setting authority key ID: %s?\n", gnutls_strerror(ret));
                goto err;
        }

        ret = gnutls_x509_crt_sign(crt, ca_crt, ca_key);
        if ( ret < 0 ) {
                fprintf(stderr, "error signing certificate: %s.\n", gnutls_strerror(ret));
                goto err;
        }

        return crt;

 err:
        gnutls_x509_crt_deinit(crt);
        return NULL;
}
Esempio n. 7
0
QString Cert::sha1_hash()
{
    if (imported == false) {
        return "";
    }

    unsigned char id[32];
    size_t len = sizeof(id);
    int ret = gnutls_x509_crt_get_key_id(this->crt, 0, id, &len);
    if (ret < 0) {
        this->last_err = gnutls_strerror(ret);
        return "";
    }

    QByteArray array;
    array.append((const char*)id, len);
    QByteArray hex = array.toHex();
    QString s = QObject::tr("SHA1:") + hex;
    return s;
}
Esempio n. 8
0
/**
 * gnutls_pkcs11_copy_x509_crt:
 * @token_url: A PKCS #11 URL specifying a token
 * @crt: A certificate
 * @label: A name to be used for the stored data
 * @flags: One of GNUTLS_PKCS11_OBJ_FLAG_*
 *
 * This function will copy a certificate into a PKCS #11 token specified by
 * a URL. The certificate can be marked as trusted or not.
 *
 * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
 *   negative error value.
 **/
int
gnutls_pkcs11_copy_x509_crt (const char *token_url,
                             gnutls_x509_crt_t crt, const char *label,
                             unsigned int flags)
{
    int ret;
    pakchois_session_t *pks;
    struct pkcs11_url_info info;
    ck_rv_t rv;
    size_t der_size, id_size;
    opaque *der = NULL;
    opaque id[20];
    struct ck_attribute a[8];
    ck_object_class_t class = CKO_CERTIFICATE;
    ck_certificate_type_t type = CKC_X_509;
    ck_object_handle_t obj;
    unsigned int tval = 1;
    int a_val;

    ret = pkcs11_url_to_info (token_url, &info);
    if (ret < 0)
    {
        gnutls_assert ();
        return ret;
    }

    ret =
        pkcs11_open_session (&pks, &info,
                             SESSION_WRITE | pkcs11_obj_flags_to_int (flags));
    if (ret < 0)
    {
        gnutls_assert ();
        return ret;
    }

    ret = gnutls_x509_crt_export (crt, GNUTLS_X509_FMT_DER, NULL, &der_size);
    if (ret < 0 && ret != GNUTLS_E_SHORT_MEMORY_BUFFER)
    {
        gnutls_assert ();
        goto cleanup;
    }

    der = gnutls_malloc (der_size);
    if (der == NULL)
    {
        gnutls_assert ();
        ret = GNUTLS_E_MEMORY_ERROR;
        goto cleanup;
    }

    ret = gnutls_x509_crt_export (crt, GNUTLS_X509_FMT_DER, der, &der_size);
    if (ret < 0)
    {
        gnutls_assert ();
        goto cleanup;
    }

    id_size = sizeof (id);
    ret = gnutls_x509_crt_get_key_id (crt, 0, id, &id_size);
    if (ret < 0)
    {
        gnutls_assert ();
        goto cleanup;
    }

    /* FIXME: copy key usage flags */

    a[0].type = CKA_CLASS;
    a[0].value = &class;
    a[0].value_len = sizeof (class);
    a[1].type = CKA_ID;
    a[1].value = id;
    a[1].value_len = id_size;
    a[2].type = CKA_VALUE;
    a[2].value = der;
    a[2].value_len = der_size;
    a[3].type = CKA_TOKEN;
    a[3].value = &tval;
    a[3].value_len = sizeof (tval);
    a[4].type = CKA_CERTIFICATE_TYPE;
    a[4].value = &type;
    a[4].value_len = sizeof (type);

    a_val = 5;

    if (label)
    {
        a[a_val].type = CKA_LABEL;
        a[a_val].value = (void *) label;
        a[a_val].value_len = strlen (label);
        a_val++;
    }

    if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_TRUSTED)
    {
        a[a_val].type = CKA_TRUSTED;
        a[a_val].value = &tval;
        a[a_val].value_len = sizeof (tval);
        a_val++;
    }

    rv = pakchois_create_object (pks, a, a_val, &obj);
    if (rv != CKR_OK)
    {
        gnutls_assert ();
        _gnutls_debug_log ("pkcs11: %s\n", pakchois_error (rv));
        ret = pkcs11_rv_to_err (rv);
        goto cleanup;
    }

    /* generated!
     */

    ret = 0;

cleanup:
    gnutls_free (der);
    pakchois_close_session (pks);

    return ret;

}
Esempio n. 9
0
/**
 * gnutls_pkcs11_copy_x509_crt2:
 * @token_url: A PKCS #11 URL specifying a token
 * @crt: The certificate to copy
 * @label: The name to be used for the stored data
 * @cid: The CKA_ID to set for the object -if NULL, the ID will be derived from the public key
 * @flags: One of GNUTLS_PKCS11_OBJ_FLAG_*
 *
 * This function will copy a certificate into a PKCS #11 token specified by
 * a URL. Valid flags to mark the certificate: %GNUTLS_PKCS11_OBJ_FLAG_MARK_TRUSTED,
 * %GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE, %GNUTLS_PKCS11_OBJ_FLAG_MARK_PRIVATE,
 * %GNUTLS_PKCS11_OBJ_FLAG_MARK_CA, %GNUTLS_PKCS11_OBJ_FLAG_MARK_ALWAYS_AUTH.
 *
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
 *   negative error value.
 *
 * Since: 3.4.0
 **/
int
gnutls_pkcs11_copy_x509_crt2(const char *token_url,
			    gnutls_x509_crt_t crt, const char *label,
			    const gnutls_datum_t *cid,
			    unsigned int flags)
{
	int ret;
	struct p11_kit_uri *info = NULL;
	ck_rv_t rv;
	size_t der_size, id_size, serial_size;
	gnutls_datum_t serial_der = {NULL, 0};
	uint8_t *der = NULL;
	uint8_t serial[128];
	uint8_t id[20];
	struct ck_attribute a[MAX_ASIZE];
	ck_object_class_t class = CKO_CERTIFICATE;
	ck_certificate_type_t type = CKC_X_509;
	ck_object_handle_t ctx;
	unsigned a_val;
	struct pkcs11_session_info sinfo;
	
	PKCS11_CHECK_INIT;

	ret = pkcs11_url_to_info(token_url, &info, 0);
	if (ret < 0) {
		gnutls_assert();
		return ret;
	}

	ret =
	    pkcs11_open_session(&sinfo, NULL, info,
				SESSION_WRITE |
				pkcs11_obj_flags_to_int(flags));
	p11_kit_uri_free(info);

	if (ret < 0) {
		gnutls_assert();
		return ret;
	}

	der_size = 0;
	ret =
	    gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_DER, NULL,
				   &der_size);
	if (ret < 0 && ret != GNUTLS_E_SHORT_MEMORY_BUFFER) {
		gnutls_assert();
		goto cleanup;
	}

	der = gnutls_malloc(der_size);
	if (der == NULL) {
		gnutls_assert();
		ret = GNUTLS_E_MEMORY_ERROR;
		goto cleanup;
	}

	ret =
	    gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_DER, der,
				   &der_size);
	if (ret < 0) {
		gnutls_assert();
		goto cleanup;
	}

	a[0].type = CKA_CLASS;
	a[0].value = &class;
	a[0].value_len = sizeof(class);

	a[1].type = CKA_ID;
	if (cid == NULL || cid->size == 0) {
		id_size = sizeof(id);
		ret = gnutls_x509_crt_get_subject_key_id(crt, id, &id_size, NULL);
		if (ret < 0) {
			id_size = sizeof(id);
			ret = gnutls_x509_crt_get_key_id(crt, 0, id, &id_size);
			if (ret < 0) {
			  gnutls_assert();
			  goto cleanup;
			}
		}

		a[1].value = id;
		a[1].value_len = id_size;
	} else {
		a[1].value = cid->data;
		a[1].value_len = cid->size;
	}

	a[2].type = CKA_VALUE;
	a[2].value = der;
	a[2].value_len = der_size;
	a[3].type = CKA_TOKEN;
	a[3].value = (void *) &tval;
	a[3].value_len = sizeof(tval);
	a[4].type = CKA_CERTIFICATE_TYPE;
	a[4].value = &type;
	a[4].value_len = sizeof(type);
	/* FIXME: copy key usage flags */

	a_val = 5;

	a[a_val].type = CKA_SUBJECT;
	a[a_val].value = crt->raw_dn.data;
	a[a_val].value_len = crt->raw_dn.size;
	a_val++;

	a[a_val].type = CKA_ISSUER;
	a[a_val].value = crt->raw_issuer_dn.data;
	a[a_val].value_len = crt->raw_issuer_dn.size;
	a_val++;

	serial_size = sizeof(serial);
	if (gnutls_x509_crt_get_serial(crt, serial, &serial_size) >= 0) {
		ret = _gnutls_x509_ext_gen_number(serial, serial_size, &serial_der);
		if (ret >= 0) {
			a[a_val].type = CKA_SERIAL_NUMBER;
			a[a_val].value = (void *) serial_der.data;
			a[a_val].value_len = serial_der.size;
			a_val++;
		}
	}

	if (label) {
		a[a_val].type = CKA_LABEL;
		a[a_val].value = (void *) label;
		a[a_val].value_len = strlen(label);
		a_val++;
	}

	mark_flags(flags, a, &a_val, sinfo.trusted);

	rv = pkcs11_create_object(sinfo.module, sinfo.pks, a, a_val, &ctx);
	if (rv != CKR_OK) {
		gnutls_assert();
		_gnutls_debug_log("p11: %s\n", pkcs11_strerror(rv));
		ret = pkcs11_rv_to_err(rv);
		goto cleanup;
	}

	/* generated! 
	 */

	ret = 0;

      cleanup:
	gnutls_free(der);
	gnutls_free(serial_der.data);
	pkcs11_close_session(&sinfo);
	return ret;

}
Esempio n. 10
0
/* 
   auto-generate a set of self signed certificates
*/
void tls_cert_generate(TALLOC_CTX *mem_ctx, 
		       const char *hostname, 
		       const char *keyfile, const char *certfile,
		       const char *cafile)
{
	gnutls_x509_crt cacrt, crt;
	gnutls_x509_privkey key, cakey;
	uint32_t serial = (uint32_t)time(NULL);
	unsigned char keyid[100];
	char buf[4096];
	size_t bufsize;
	size_t keyidsize = sizeof(keyid);
	time_t activation = time(NULL), expiry = activation + LIFETIME;
	int ret;

	if (file_exist(keyfile) || file_exist(certfile) || file_exist(cafile)) {
		DEBUG(0,("TLS autogeneration skipped - some TLS files already exist\n"));
		return;
	}

#define TLSCHECK(call) do { \
	ret = call; \
	if (ret < 0) { \
		DEBUG(0,("TLS %s - %s\n", #call, gnutls_strerror(ret))); \
		goto failed; \
	} \
} while (0)

	TLSCHECK(gnutls_global_init());

	DEBUG(0,("Attempting to autogenerate TLS self-signed keys for https for hostname '%s'\n", 
		 hostname));
	
#if defined(HAVE_GCRYPT_H) && !defined(HAVE_GNUTLS3)
	DEBUG(3,("Enabling QUICK mode in gcrypt\n"));
	gcry_control(GCRYCTL_ENABLE_QUICK_RANDOM, 0);
#endif

	DEBUG(3,("Generating private key\n"));
	TLSCHECK(gnutls_x509_privkey_init(&key));
	TLSCHECK(gnutls_x509_privkey_generate(key,   GNUTLS_PK_RSA, RSA_BITS, 0));

	DEBUG(3,("Generating CA private key\n"));
	TLSCHECK(gnutls_x509_privkey_init(&cakey));
	TLSCHECK(gnutls_x509_privkey_generate(cakey, GNUTLS_PK_RSA, RSA_BITS, 0));

	DEBUG(3,("Generating CA certificate\n"));
	TLSCHECK(gnutls_x509_crt_init(&cacrt));
	TLSCHECK(gnutls_x509_crt_set_dn_by_oid(cacrt, 
				      GNUTLS_OID_X520_ORGANIZATION_NAME, 0,
				      ORGANISATION_NAME, strlen(ORGANISATION_NAME)));
	TLSCHECK(gnutls_x509_crt_set_dn_by_oid(cacrt, 
				      GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME, 0,
				      CA_NAME, strlen(CA_NAME)));
	TLSCHECK(gnutls_x509_crt_set_dn_by_oid(cacrt,
				      GNUTLS_OID_X520_COMMON_NAME, 0,
				      hostname, strlen(hostname)));
	TLSCHECK(gnutls_x509_crt_set_key(cacrt, cakey));
	TLSCHECK(gnutls_x509_crt_set_serial(cacrt, &serial, sizeof(serial)));
	TLSCHECK(gnutls_x509_crt_set_activation_time(cacrt, activation));
	TLSCHECK(gnutls_x509_crt_set_expiration_time(cacrt, expiry));
	TLSCHECK(gnutls_x509_crt_set_ca_status(cacrt, 1));
	TLSCHECK(gnutls_x509_crt_set_key_usage(cacrt, GNUTLS_KEY_KEY_CERT_SIGN | GNUTLS_KEY_CRL_SIGN));
	TLSCHECK(gnutls_x509_crt_set_version(cacrt, 3));
	TLSCHECK(gnutls_x509_crt_get_key_id(cacrt, 0, keyid, &keyidsize));
#if HAVE_GNUTLS_X509_CRT_SET_SUBJECT_KEY_ID
	TLSCHECK(gnutls_x509_crt_set_subject_key_id(cacrt, keyid, keyidsize));
#endif
	TLSCHECK(gnutls_x509_crt_sign2(cacrt, cacrt, cakey,
				       GNUTLS_DIG_SHA256, 0));

	DEBUG(3,("Generating TLS certificate\n"));
	TLSCHECK(gnutls_x509_crt_init(&crt));
	TLSCHECK(gnutls_x509_crt_set_dn_by_oid(crt, 
				      GNUTLS_OID_X520_ORGANIZATION_NAME, 0,
				      ORGANISATION_NAME, strlen(ORGANISATION_NAME)));
	TLSCHECK(gnutls_x509_crt_set_dn_by_oid(crt, 
				      GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME, 0,
				      UNIT_NAME, strlen(UNIT_NAME)));
	TLSCHECK(gnutls_x509_crt_set_dn_by_oid(crt,
				      GNUTLS_OID_X520_COMMON_NAME, 0,
				      hostname, strlen(hostname)));
	TLSCHECK(gnutls_x509_crt_set_key(crt, key));
	TLSCHECK(gnutls_x509_crt_set_serial(crt, &serial, sizeof(serial)));
	TLSCHECK(gnutls_x509_crt_set_activation_time(crt, activation));
	TLSCHECK(gnutls_x509_crt_set_expiration_time(crt, expiry));
	TLSCHECK(gnutls_x509_crt_set_ca_status(crt, 0));
#ifdef GNUTLS_KP_TLS_WWW_SERVER
	TLSCHECK(gnutls_x509_crt_set_key_purpose_oid(crt, GNUTLS_KP_TLS_WWW_SERVER, 0));
#endif
	TLSCHECK(gnutls_x509_crt_set_version(crt, 3));
	TLSCHECK(gnutls_x509_crt_get_key_id(crt, 0, keyid, &keyidsize));
#if HAVE_GNUTLS_X509_CRT_SET_SUBJECT_KEY_ID
	TLSCHECK(gnutls_x509_crt_set_subject_key_id(crt, keyid, keyidsize));
#endif
	TLSCHECK(gnutls_x509_crt_sign2(crt, crt, key,
				       GNUTLS_DIG_SHA256, 0));
	TLSCHECK(gnutls_x509_crt_sign2(crt, cacrt, cakey,
				       GNUTLS_DIG_SHA256, 0));

	DEBUG(3,("Exporting TLS keys\n"));

	bufsize = sizeof(buf);
	TLSCHECK(gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_PEM, buf, &bufsize));
	if (!file_save(certfile, buf, bufsize)) {
		DEBUG(0,("Unable to save certificate in %s parent dir exists ?\n", certfile));
		goto failed;
	}

	bufsize = sizeof(buf);
	TLSCHECK(gnutls_x509_crt_export(cacrt, GNUTLS_X509_FMT_PEM, buf, &bufsize));
	if (!file_save(cafile, buf, bufsize)) {
		DEBUG(0,("Unable to save ca cert in %s parent dir exists ?\n", cafile));
		goto failed;
	}

	bufsize = sizeof(buf);
	TLSCHECK(gnutls_x509_privkey_export(key, GNUTLS_X509_FMT_PEM, buf, &bufsize));
	if (!file_save_mode(keyfile, buf, bufsize, 0600)) {
		DEBUG(0,("Unable to save privatekey in %s parent dir exists ?\n", keyfile));
		goto failed;
	}

	gnutls_x509_privkey_deinit(key);
	gnutls_x509_privkey_deinit(cakey);
	gnutls_x509_crt_deinit(cacrt);
	gnutls_x509_crt_deinit(crt);
	gnutls_global_deinit();

	DEBUG(0,("TLS self-signed keys generated OK\n"));
	return;

failed:
	DEBUG(0,("TLS certificate generation failed\n"));
}
Esempio n. 11
0
bool load_p12(gnutls_certificate_credentials_t xcred,
				  const char *const p12_file,
				  const char *const password)
{
	FILE*p12file;
	gnutls_datum_t p12blob;
	gnutls_pkcs12_t p12 = NULL;

	gnutls_x509_privkey_t key = NULL;
	gnutls_x509_crt_t certs[MAX_CERTS];
	int certs_nr;
	int id_cert;

	uint8_t key_id[20];
	size_t key_id_size;

	bool is_success = false;
	int ret;
	int i;

	assert(p12_file != NULL);

	/* Read file */
	p12file = fopen(p12_file, "rb");
	if(p12file == NULL)
	{
		trace(LOG_ERR, "failed to open PKCS#12 file '%s': %s (%d)", p12_file,
				strerror(errno), errno);
		ret = GNUTLS_E_FILE_ERROR;
		goto error;
	}
	p12blob.data = malloc(32768 * sizeof(char));
	p12blob.size = fread((void*) p12blob.data, sizeof(char), 32768, p12file);
	fclose(p12file);

	/* Init structure and import P12 */
	ret = gnutls_pkcs12_init(&p12);
	if(ret < 0)
	{
		trace(LOG_ERR, "failed to init PKCS#12 object (%d)", ret);
		goto free_blob;
	}

	ret = gnutls_pkcs12_import(p12, &p12blob, GNUTLS_X509_FMT_DER, 0);
	if(ret < 0)
	{
		trace(LOG_ERR, "failed to import PKCS#12 data (%d)", ret);
		goto deinit_pkcs12;
	}

	if(password)
	{
		ret = gnutls_pkcs12_verify_mac(p12, password);
		if(ret < 0)
		{
			trace(LOG_ERR, "failed to verify PKCS#12 MAC (%d)", ret);
			goto deinit_pkcs12;
		}
	}

	/* extract the private key and the certificates from PKCS#12 */
	if(!tls_parse_pkcs12(&p12, password, &key, certs, &certs_nr))
	{
		trace(LOG_ERR, "failed to parse PKCS#12 file '%s'", p12_file);
		goto deinit_pkcs12;
	}
	if(certs_nr < 2)
	{
		trace(LOG_ERR, "too few certificates in PKCS#12 file '%s'", p12_file);
		goto free_certs_key;
	}
	
	/* get the ID of private key */
	key_id_size = sizeof(key_id);
	ret = gnutls_x509_privkey_get_key_id(key, 0, key_id, &key_id_size);
	if(ret < 0)
	{
		trace(LOG_ERR, "failed to get key ID");
		goto free_certs_key;
	}

	id_cert = -1;
	for(i = 0; i < certs_nr; i++)
	{
		uint8_t cert_id[20];
		size_t cert_id_size;

		cert_id_size = sizeof(cert_id);
		ret = gnutls_x509_crt_get_key_id(certs[i], 0, cert_id, &cert_id_size);
		if(ret < 0)
		{
			trace(LOG_ERR, "failed to get key ID for certificate #%d (%d)", i, ret);
			goto free_certs_key;
		}

		if(key_id_size == cert_id_size &&
			memcmp(cert_id, key_id, cert_id_size) == 0)
		{
			/* it's the key certificate ! */
			if(id_cert != -1)
			{
				ret = GNUTLS_E_INTERRUPTED;
				trace(LOG_ERR, "Duplicate key certificate !\n");
				goto free_certs_key;
			}
			id_cert = i;
		}
	}

	if(id_cert == -1)
	{
		ret = GNUTLS_E_INTERRUPTED;
		trace(LOG_ERR, "Unable to find key certificate !\n");
		goto free_certs_key;
	}

	/* Now have fun with the key and certs ! */
	ret = gnutls_certificate_set_x509_key(xcred, &certs[id_cert], 1, key);
	if(ret < 0)
	{
		trace(LOG_ERR, "failed to set key for main certificate");
		goto free_certs_key;
	}

	for(i = 0; i < certs_nr; i++)
	{
		if(i != id_cert)
		{
			ret = gnutls_certificate_set_x509_trust(xcred, &certs[i], 1);
			if(ret < 0)
			{
				trace(LOG_ERR, "failed to trust certificate #%d", i + 1);
				goto free_certs_key;
			}
		}
	}

	is_success = true;

free_certs_key:
	gnutls_x509_privkey_deinit(key);
	for(i = 0; i < certs_nr; i++)
	{
		gnutls_x509_crt_deinit(certs[i]);
	}
deinit_pkcs12:
	gnutls_pkcs12_deinit(p12);
free_blob:
	free(p12blob.data);
error:
	return is_success;
}
Esempio n. 12
0
/**
 * gnutls_system_key_add_x509:
 * @crt: the certificate to be added
 * @privkey: the key to be added
 * @label: the friendly name to describe the key
 * @cert_url: if non-NULL it will contain an allocated value with the certificate URL
 * @key_url: if non-NULL it will contain an allocated value with the key URL
 *
 * This function will added the given key and certificate pair,
 * to the system list.
 *
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
 *   negative error value.
 *
 * Since: 3.4.0
 **/
int gnutls_system_key_add_x509(gnutls_x509_crt_t crt,
			       gnutls_x509_privkey_t privkey, const char *label,
			       char **cert_url, char **key_url)
{
	HCERTSTORE store = NULL;
	CRYPT_DATA_BLOB pfx;
	gnutls_datum_t _pfx = { NULL, 0 };
	gnutls_pkcs12_t p12 = NULL;
	gnutls_pkcs12_bag_t bag1 = NULL, bag2 = NULL;
	uint8_t id[MAX_WID_SIZE];
	size_t id_size;
	gnutls_datum_t kid;
	int ret;

	if (ncrypt_init == 0)
		return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE);

	if (label == NULL)
		return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);

	id_size = sizeof(id);
	ret = gnutls_x509_crt_get_key_id(crt, 0, id, &id_size);
	if (ret < 0)
		return gnutls_assert_val(ret);

	kid.data = id;
	kid.size = id_size;

	/* the idea: import the cert and private key into PKCS #12
	 * format, export it into pfx, and import it into store */
	ret = gnutls_pkcs12_init(&p12);
	if (ret < 0)
		return gnutls_assert_val(ret);

	ret = gnutls_pkcs12_bag_init(&bag1);
	if (ret < 0) {
		gnutls_assert();
		goto cleanup;
	}

	ret = gnutls_pkcs12_bag_set_crt(bag1, crt);
	if (ret < 0) {
		gnutls_assert();
		goto cleanup;
	}

	ret = gnutls_pkcs12_bag_set_key_id(bag1, 0, &kid);
	if (ret < 0) {
		gnutls_assert();
		goto cleanup;
	}

	if (label)
		gnutls_pkcs12_bag_set_friendly_name(bag1, 0, label);

	ret = gnutls_pkcs12_bag_init(&bag2);
	if (ret < 0) {
		gnutls_assert();
		goto cleanup;
	}

	ret = gnutls_pkcs12_bag_set_privkey(bag2, privkey, NULL, 0);
	if (ret < 0) {
		gnutls_assert();
		goto cleanup;
	}

	ret = gnutls_pkcs12_bag_set_key_id(bag2, 0, &kid);
	if (ret < 0) {
		gnutls_assert();
		goto cleanup;
	}

	if (label)
		gnutls_pkcs12_bag_set_friendly_name(bag2, 0, label);

	ret = gnutls_pkcs12_set_bag(p12, bag1);
	if (ret < 0) {
		gnutls_assert();
		goto cleanup;
	}

	ret = gnutls_pkcs12_set_bag(p12, bag2);
	if (ret < 0) {
		gnutls_assert();
		goto cleanup;
	}

	ret = gnutls_pkcs12_generate_mac(p12, "123456");
	if (ret < 0) {
		gnutls_assert();
		goto cleanup;
	}

	ret = gnutls_pkcs12_export2(p12, GNUTLS_X509_FMT_DER, &_pfx);
	if (ret < 0) {
		gnutls_assert();
		goto cleanup;
	}

	pfx.cbData = _pfx.size;
	pfx.pbData = _pfx.data;

	store = PFXImportCertStore(&pfx, L"123456", 0);
	if (store == NULL) {
		gnutls_assert();
		ret = GNUTLS_E_INVALID_REQUEST;
		goto cleanup;
	}

	if (cert_url || key_url) {
		unsigned char sha[20];
		CRYPT_HASH_BLOB blob;
		const CERT_CONTEXT *cert = NULL;
		gnutls_datum_t data;

		ret = gnutls_x509_crt_export2(crt, GNUTLS_X509_FMT_DER, &data);
		if (ret < 0) {
			gnutls_assert();
			goto cleanup;
		}

		ret =
		    gnutls_hash_fast(GNUTLS_DIG_SHA1, data.data, data.size,
				     sha);
		gnutls_free(data.data);
		if (ret < 0) {
			gnutls_assert();
			goto cleanup;
		}

		blob.cbData = sizeof(sha);
		blob.pbData = sha;

		cert = CertFindCertificateInStore(store,
						  X509_ASN_ENCODING,
						  0,
						  CERT_FIND_SHA1_HASH,
						  &blob, NULL);

		if (cert == NULL) {
			gnutls_assert();
			ret = GNUTLS_E_KEY_IMPORT_FAILED;
			goto cleanup;
		}

		ret = get_win_urls(cert, cert_url, key_url, NULL, NULL);
		if (ret < 0) {
			gnutls_assert();
			goto cleanup;
		}
	}

	ret = 0;

 cleanup:
	if (p12 != NULL)
		gnutls_pkcs12_deinit(p12);
	if (bag1 != NULL)
		gnutls_pkcs12_bag_deinit(bag1);
	if (bag2 != NULL)
		gnutls_pkcs12_bag_deinit(bag2);
	if (store != NULL)
		CertCloseStore(store, 0);
	gnutls_free(_pfx.data);
	return ret;
}
Esempio n. 13
0
/**
 * gnutls_pkcs11_copy_x509_crt:
 * @token_url: A PKCS #11 URL specifying a token
 * @crt: A certificate
 * @label: A name to be used for the stored data
 * @flags: One of GNUTLS_PKCS11_OBJ_FLAG_*
 *
 * This function will copy a certificate into a PKCS #11 token specified by
 * a URL. The certificate can be marked as trusted or not.
 *
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
 *   negative error value.
 *
 * Since: 2.12.0
 **/
int
gnutls_pkcs11_copy_x509_crt(const char *token_url,
			    gnutls_x509_crt_t crt, const char *label,
			    unsigned int flags)
{
	int ret;
	struct p11_kit_uri *info = NULL;
	ck_rv_t rv;
	size_t der_size, id_size;
	uint8_t *der = NULL;
	uint8_t id[20];
	struct ck_attribute a[16];
	ck_object_class_t class = CKO_CERTIFICATE;
	ck_certificate_type_t type = CKC_X_509;
	ck_object_handle_t obj;
	int a_val;
	unsigned long category;
	struct pkcs11_session_info sinfo;
	
	PKCS11_CHECK_INIT;

	memset(&sinfo, 0, sizeof(sinfo));

	ret = pkcs11_url_to_info(token_url, &info);
	if (ret < 0) {
		gnutls_assert();
		return ret;
	}

	ret =
	    pkcs11_open_session(&sinfo, NULL, info,
				SESSION_WRITE |
				pkcs11_obj_flags_to_int(flags));
	p11_kit_uri_free(info);

	if (ret < 0) {
		gnutls_assert();
		return ret;
	}

	der_size = 0;
	ret =
	    gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_DER, NULL,
				   &der_size);
	if (ret < 0 && ret != GNUTLS_E_SHORT_MEMORY_BUFFER) {
		gnutls_assert();
		goto cleanup;
	}

	der = gnutls_malloc(der_size);
	if (der == NULL) {
		gnutls_assert();
		ret = GNUTLS_E_MEMORY_ERROR;
		goto cleanup;
	}

	ret =
	    gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_DER, der,
				   &der_size);
	if (ret < 0) {
		gnutls_assert();
		goto cleanup;
	}

	id_size = sizeof(id);
	ret = gnutls_x509_crt_get_subject_key_id(crt, id, &id_size, NULL);
	if (ret < 0) {
	        id_size = sizeof(id);
		ret = gnutls_x509_crt_get_key_id(crt, 0, id, &id_size);
		if (ret < 0) {
		  gnutls_assert();
		  goto cleanup;
                }
	}

	/* FIXME: copy key usage flags */

	a[0].type = CKA_CLASS;
	a[0].value = &class;
	a[0].value_len = sizeof(class);
	a[1].type = CKA_ID;
	a[1].value = id;
	a[1].value_len = id_size;
	a[2].type = CKA_VALUE;
	a[2].value = der;
	a[2].value_len = der_size;
	a[3].type = CKA_TOKEN;
	a[3].value = (void *) &tval;
	a[3].value_len = sizeof(tval);
	a[4].type = CKA_CERTIFICATE_TYPE;
	a[4].value = &type;
	a[4].value_len = sizeof(type);

	a_val = 5;

	a[a_val].type = CKA_SUBJECT;
	a[a_val].value = crt->raw_dn.data;
	a[a_val].value_len = crt->raw_dn.size;
	a_val++;

	if (label) {
		a[a_val].type = CKA_LABEL;
		a[a_val].value = (void *) label;
		a[a_val].value_len = strlen(label);
		a_val++;
	}

	if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_CA) {
		category = 2;
		a[a_val].type = CKA_CERTIFICATE_CATEGORY;
		a[a_val].value = (void *) &category;
		a[a_val].value_len = sizeof(category);
		a_val++;
	}

	if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_TRUSTED) {
		a[a_val].type = CKA_TRUSTED;
		a[a_val].value = (void *) &tval;
		a[a_val].value_len = sizeof(tval);
		a_val++;

		a[a_val].type = CKA_PRIVATE;
		a[a_val].value = (void *) &fval;
		a[a_val].value_len = sizeof(fval);
		a_val++;
	} else {
		if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_PRIVATE) {
			a[a_val].type = CKA_PRIVATE;
			a[a_val].value = (void *) &tval;
			a[a_val].value_len = sizeof(tval);
			a_val++;
		} else if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_NOT_PRIVATE) {
			a[a_val].type = CKA_PRIVATE;
			a[a_val].value = (void *) &fval;
			a[a_val].value_len = sizeof(fval);
			a_val++;
		}
	}

	rv = pkcs11_create_object(sinfo.module, sinfo.pks, a, a_val, &obj);
	if (rv != CKR_OK) {
		gnutls_assert();
		_gnutls_debug_log("p11: %s\n", pkcs11_strerror(rv));
		ret = pkcs11_rv_to_err(rv);
		goto cleanup;
	}

	/* generated! 
	 */

	ret = 0;

      cleanup:
	gnutls_free(der);
	pkcs11_close_session(&sinfo);
	return ret;

}
Esempio n. 14
0
void    Plugin::_loadCertificate()
{
    QFile            file(this->crtFile);
    gnutls_datum_t   datum;
    size_t           size = 2048;
    QByteArray       data;
    gnutls_privkey_t privkey;
    gnutls_pubkey_t  pubkey;
    gnutls_pubkey_t  pubkeyCrt;
    int              error;
    QMap<char *, QByteArray> oid;
    gnutls_digest_algorithm_t digest;

    if (!file.open(QIODevice::ReadWrite))
        throw Properties("error", "Unable to open the certificate file").add("file", this->crtFile);
    ASSERT_INIT(gnutls_x509_crt_init(&this->crt), "crt");
    ASSERT(gnutls_privkey_init(&privkey));
    ASSERT(gnutls_privkey_import_x509(privkey, this->key, 0));
    ASSERT(gnutls_pubkey_init(&pubkey));
    ASSERT(gnutls_pubkey_import_privkey(pubkey, privkey, 0, 0));
    // Verifies that the certificate is valid
    if (file.size() > 0)
    {
        ASSERT(gnutls_pubkey_init(&pubkeyCrt));
        data = file.readAll();
        datum.size = data.size();
        datum.data = (unsigned char *)data.data();
        if (gnutls_x509_crt_import(this->crt, &datum, GNUTLS_X509_FMT_PEM) != GNUTLS_E_SUCCESS)
            file.resize(0);
        else if (gnutls_x509_crt_get_expiration_time(this->crt) < ::time(NULL) + CRT_EXPIRATION_REGEN)
            file.resize(0);
        else if (gnutls_pubkey_import_x509(pubkeyCrt, this->crt, 0) != GNUTLS_E_SUCCESS)
            file.resize(0);
        // Ensures that the public keys of the certificate and the private key match
        size_t size1 = size, size2 = size;
        QByteArray pub1((int)size1, 0), pub2((int)size2, 0);
        if (gnutls_pubkey_export(pubkey, GNUTLS_X509_FMT_PEM, pub1.data(), &size1) != GNUTLS_E_SUCCESS
            || gnutls_pubkey_export(pubkeyCrt, GNUTLS_X509_FMT_PEM, pub2.data(), &size2) != GNUTLS_E_SUCCESS
            || size1 != size2 || pub1 != pub2)
            file.resize(0);
        gnutls_pubkey_deinit(pubkeyCrt);
    }
    // Generates a new certificate
    if (file.size() == 0)
    {
        gnutls_x509_crt_deinit(this->crt);
        this->init.removeAll("crt");
        ASSERT_INIT(gnutls_x509_crt_init(&this->crt), "crt");
        LOG_INFO("Generating a new certificate", "Plugin", "_generateCertificate");
        oid.insert((char *)GNUTLS_OID_X520_COMMON_NAME, "LightBird");
        oid.insert((char *)GNUTLS_OID_X520_ORGANIZATION_NAME, "LightBird");
        QMapIterator<char *, QByteArray> it(oid);
        while (it.hasNext())
            ASSERT(gnutls_x509_crt_set_dn_by_oid(this->crt, it.key(), 0, it.value().data(), it.next().value().size()));
        ASSERT(gnutls_x509_crt_set_pubkey(this->crt, pubkey));
        data = this->_generateSerial();
        ASSERT(gnutls_x509_crt_set_serial(this->crt, data.data(), data.size()));
        ASSERT(gnutls_x509_crt_set_activation_time(this->crt, ::time(NULL)));
        ASSERT(gnutls_x509_crt_set_expiration_time(this->crt, ::time(NULL) + CRT_EXPIRATION));
        ASSERT(gnutls_x509_crt_set_basic_constraints(this->crt, 0, -1));
        ASSERT(gnutls_x509_crt_set_key_purpose_oid(this->crt, GNUTLS_KP_TLS_WWW_SERVER, 0));
        ASSERT(gnutls_x509_crt_set_key_usage(this->crt, GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT));
        data.resize((int)size);
        ASSERT(gnutls_x509_crt_get_key_id(this->crt, 0, (unsigned char *)data.data(), &size));
        ASSERT(gnutls_x509_crt_set_subject_key_id(this->crt, (unsigned char *)data.data(), size));
        ASSERT(gnutls_x509_crt_set_version(this->crt, 3));
        ASSERT(gnutls_pubkey_get_preferred_hash_algorithm(pubkey, &digest, NULL));
        ASSERT(gnutls_x509_crt_privkey_sign(this->crt, this->crt, privkey, digest, 0));
        size = data.size();
        ASSERT(gnutls_x509_crt_export(this->crt, GNUTLS_X509_FMT_PEM, data.data(), &size));
        data.resize((int)size);
        file.write(data);
    }
    gnutls_pubkey_deinit(pubkey);
    gnutls_privkey_deinit(privkey);
}
Esempio n. 15
0
int					/* O - 1 on success, 0 on failure */
cupsMakeServerCredentials(
    const char *path,			/* I - Path to keychain/directory */
    const char *common_name,		/* I - Common name */
    int        num_alt_names,		/* I - Number of subject alternate names */
    const char **alt_names,		/* I - Subject Alternate Names */
    time_t     expiration_date)		/* I - Expiration date */
{
  gnutls_x509_crt_t	crt;		/* Self-signed certificate */
  gnutls_x509_privkey_t	key;		/* Encryption private key */
  char			temp[1024],	/* Temporary directory name */
 			crtfile[1024],	/* Certificate filename */
			keyfile[1024];	/* Private key filename */
  cups_lang_t		*language;	/* Default language info */
  cups_file_t		*fp;		/* Key/cert file */
  unsigned char		buffer[8192];	/* Buffer for x509 data */
  size_t		bytes;		/* Number of bytes of data */
  unsigned char		serial[4];	/* Serial number buffer */
  time_t		curtime;	/* Current time */
  int			result;		/* Result of GNU TLS calls */


  DEBUG_printf(("cupsMakeServerCredentials(path=\"%s\", common_name=\"%s\", num_alt_names=%d, alt_names=%p, expiration_date=%d)", path, common_name, num_alt_names, alt_names, (int)expiration_date));

 /*
  * Filenames...
  */

  if (!path)
    path = http_gnutls_default_path(temp, sizeof(temp));

  if (!path || !common_name)
  {
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);
    return (0);
  }

  http_gnutls_make_path(crtfile, sizeof(crtfile), path, common_name, "crt");
  http_gnutls_make_path(keyfile, sizeof(keyfile), path, common_name, "key");

 /*
  * Create the encryption key...
  */

  DEBUG_puts("1cupsMakeServerCredentials: Creating key pair.");

  gnutls_x509_privkey_init(&key);
  gnutls_x509_privkey_generate(key, GNUTLS_PK_RSA, 2048, 0);

  DEBUG_puts("1cupsMakeServerCredentials: Key pair created.");

 /*
  * Save it...
  */

  bytes = sizeof(buffer);

  if ((result = gnutls_x509_privkey_export(key, GNUTLS_X509_FMT_PEM, buffer, &bytes)) < 0)
  {
    DEBUG_printf(("1cupsMakeServerCredentials: Unable to export private key: %s", gnutls_strerror(result)));
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, gnutls_strerror(result), 0);
    gnutls_x509_privkey_deinit(key);
    return (0);
  }
  else if ((fp = cupsFileOpen(keyfile, "w")) != NULL)
  {
    DEBUG_printf(("1cupsMakeServerCredentials: Writing private key to \"%s\".", keyfile));
    cupsFileWrite(fp, (char *)buffer, bytes);
    cupsFileClose(fp);
  }
  else
  {
    DEBUG_printf(("1cupsMakeServerCredentials: Unable to create private key file \"%s\": %s", keyfile, strerror(errno)));
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
    gnutls_x509_privkey_deinit(key);
    return (0);
  }

 /*
  * Create the self-signed certificate...
  */

  DEBUG_puts("1cupsMakeServerCredentials: Generating self-signed X.509 certificate.");

  language  = cupsLangDefault();
  curtime   = time(NULL);
  serial[0] = curtime >> 24;
  serial[1] = curtime >> 16;
  serial[2] = curtime >> 8;
  serial[3] = curtime;

  gnutls_x509_crt_init(&crt);
  if (strlen(language->language) == 5)
    gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COUNTRY_NAME, 0,
                                  language->language + 3, 2);
  else
    gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COUNTRY_NAME, 0,
                                  "US", 2);
  gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COMMON_NAME, 0,
                                common_name, strlen(common_name));
  gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_ORGANIZATION_NAME, 0,
                                common_name, strlen(common_name));
  gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME,
                                0, "Unknown", 7);
  gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME, 0,
                                "Unknown", 7);
  gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_LOCALITY_NAME, 0,
                                "Unknown", 7);
/*  gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_PKCS9_EMAIL, 0,
                                ServerAdmin, strlen(ServerAdmin));*/
  gnutls_x509_crt_set_key(crt, key);
  gnutls_x509_crt_set_serial(crt, serial, sizeof(serial));
  gnutls_x509_crt_set_activation_time(crt, curtime);
  gnutls_x509_crt_set_expiration_time(crt, curtime + 10 * 365 * 86400);
  gnutls_x509_crt_set_ca_status(crt, 0);
  if (num_alt_names > 0)
    gnutls_x509_crt_set_subject_alternative_name(crt, GNUTLS_SAN_DNSNAME, alt_names[0]);
  gnutls_x509_crt_set_key_purpose_oid(crt, GNUTLS_KP_TLS_WWW_SERVER, 0);
  gnutls_x509_crt_set_key_usage(crt, GNUTLS_KEY_KEY_ENCIPHERMENT);
  gnutls_x509_crt_set_version(crt, 3);

  bytes = sizeof(buffer);
  if (gnutls_x509_crt_get_key_id(crt, 0, buffer, &bytes) >= 0)
    gnutls_x509_crt_set_subject_key_id(crt, buffer, bytes);

  gnutls_x509_crt_sign(crt, crt, key);

 /*
  * Save it...
  */

  bytes = sizeof(buffer);
  if ((result = gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_PEM, buffer, &bytes)) < 0)
  {
    DEBUG_printf(("1cupsMakeServerCredentials: Unable to export public key and X.509 certificate: %s", gnutls_strerror(result)));
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, gnutls_strerror(result), 0);
    gnutls_x509_crt_deinit(crt);
    gnutls_x509_privkey_deinit(key);
    return (0);
  }
  else if ((fp = cupsFileOpen(crtfile, "w")) != NULL)
  {
    DEBUG_printf(("1cupsMakeServerCredentials: Writing public key and X.509 certificate to \"%s\".", crtfile));
    cupsFileWrite(fp, (char *)buffer, bytes);
    cupsFileClose(fp);
  }
  else
  {
    DEBUG_printf(("1cupsMakeServerCredentials: Unable to create public key and X.509 certificate file \"%s\": %s", crtfile, strerror(errno)));
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
    gnutls_x509_crt_deinit(crt);
    gnutls_x509_privkey_deinit(key);
    return (0);
  }

 /*
  * Cleanup...
  */

  gnutls_x509_crt_deinit(crt);
  gnutls_x509_privkey_deinit(key);

  DEBUG_puts("1cupsMakeServerCredentials: Successfully created credentials.");

  return (1);
}
Esempio n. 16
0
/**
 * gnutls_pkcs12_simple_parse:
 * @p12: A pkcs12 type
 * @password: optional password used to decrypt the structure, bags and keys.
 * @key: a structure to store the parsed private key.
 * @chain: the corresponding to key certificate chain (may be %NULL)
 * @chain_len: will be updated with the number of additional (may be %NULL)
 * @extra_certs: optional pointer to receive an array of additional
 *	       certificates found in the PKCS12 structure (may be %NULL).
 * @extra_certs_len: will be updated with the number of additional
 *		   certs (may be %NULL).
 * @crl: an optional structure to store the parsed CRL (may be %NULL).
 * @flags: should be zero or one of GNUTLS_PKCS12_SP_*
 *
 * This function parses a PKCS12 structure in @pkcs12 and extracts the
 * private key, the corresponding certificate chain, any additional
 * certificates and a CRL. The structures in @key, @chain @crl, and @extra_certs
 * must not be initialized.
 *
 * The @extra_certs and @extra_certs_len parameters are optional
 * and both may be set to %NULL. If either is non-%NULL, then both must
 * be set. The value for @extra_certs is allocated
 * using gnutls_malloc().
 * 
 * Encrypted PKCS12 bags and PKCS8 private keys are supported, but
 * only with password based security and the same password for all
 * operations.
 *
 * Note that a PKCS12 structure may contain many keys and/or certificates,
 * and there is no way to identify which key/certificate pair you want.
 * For this reason this function is useful for PKCS12 files that contain 
 * only one key/certificate pair and/or one CRL.
 *
 * If the provided structure has encrypted fields but no password
 * is provided then this function returns %GNUTLS_E_DECRYPTION_FAILED.
 *
 * Note that normally the chain constructed does not include self signed
 * certificates, to comply with TLS' requirements. If, however, the flag 
 * %GNUTLS_PKCS12_SP_INCLUDE_SELF_SIGNED is specified then
 * self signed certificates will be included in the chain.
 *
 * Prior to using this function the PKCS #12 structure integrity must
 * be verified using gnutls_pkcs12_verify_mac().
 *
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
 *   negative error value.
 *
 * Since: 3.1.0
 **/
int
gnutls_pkcs12_simple_parse(gnutls_pkcs12_t p12,
			   const char *password,
			   gnutls_x509_privkey_t * key,
			   gnutls_x509_crt_t ** chain,
			   unsigned int *chain_len,
			   gnutls_x509_crt_t ** extra_certs,
			   unsigned int *extra_certs_len,
			   gnutls_x509_crl_t * crl, unsigned int flags)
{
	gnutls_pkcs12_bag_t bag = NULL;
	gnutls_x509_crt_t *_extra_certs = NULL;
	unsigned int _extra_certs_len = 0;
	gnutls_x509_crt_t *_chain = NULL;
	unsigned int _chain_len = 0;
	int idx = 0;
	int ret;
	size_t cert_id_size = 0;
	size_t key_id_size = 0;
	uint8_t cert_id[20];
	uint8_t key_id[20];
	int privkey_ok = 0;
	unsigned int i;
	int elements_in_bag;

	*key = NULL;

	if (crl)
		*crl = NULL;

	/* find the first private key */
	for (;;) {

		ret = gnutls_pkcs12_bag_init(&bag);
		if (ret < 0) {
			bag = NULL;
			gnutls_assert();
			goto done;
		}

		ret = gnutls_pkcs12_get_bag(p12, idx, bag);
		if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
			gnutls_pkcs12_bag_deinit(bag);
			bag = NULL;
			break;
		}
		if (ret < 0) {
			gnutls_assert();
			goto done;
		}

		ret = gnutls_pkcs12_bag_get_type(bag, 0);
		if (ret < 0) {
			gnutls_assert();
			goto done;
		}

		if (ret == GNUTLS_BAG_ENCRYPTED) {
			if (password == NULL) {
				ret =
				    gnutls_assert_val
				    (GNUTLS_E_DECRYPTION_FAILED);
				goto done;
			}

			ret = gnutls_pkcs12_bag_decrypt(bag, password);
			if (ret < 0) {
				gnutls_assert();
				goto done;
			}
		}

		elements_in_bag = gnutls_pkcs12_bag_get_count(bag);
		if (elements_in_bag < 0) {
			gnutls_assert();
			goto done;
		}

		for (i = 0; i < (unsigned)elements_in_bag; i++) {
			int type;
			gnutls_datum_t data;

			type = gnutls_pkcs12_bag_get_type(bag, i);
			if (type < 0) {
				gnutls_assert();
				goto done;
			}

			ret = gnutls_pkcs12_bag_get_data(bag, i, &data);
			if (ret < 0) {
				gnutls_assert();
				goto done;
			}

			switch (type) {
			case GNUTLS_BAG_PKCS8_ENCRYPTED_KEY:
				if (password == NULL) {
					ret =
					    gnutls_assert_val
					    (GNUTLS_E_DECRYPTION_FAILED);
					goto done;
				}

				FALLTHROUGH;
			case GNUTLS_BAG_PKCS8_KEY:
				if (*key != NULL) {	/* too simple to continue */
					gnutls_assert();
					break;
				}

				ret = gnutls_x509_privkey_init(key);
				if (ret < 0) {
					gnutls_assert();
					goto done;
				}

				ret = gnutls_x509_privkey_import_pkcs8
				    (*key, &data, GNUTLS_X509_FMT_DER,
				     password,
				     type ==
				     GNUTLS_BAG_PKCS8_KEY ?
				     GNUTLS_PKCS_PLAIN : 0);
				if (ret < 0) {
					gnutls_assert();
					goto done;
				}

				key_id_size = sizeof(key_id);
				ret =
				    gnutls_x509_privkey_get_key_id(*key, 0,
								   key_id,
								   &key_id_size);
				if (ret < 0) {
					gnutls_assert();
					goto done;
				}

				privkey_ok = 1;	/* break */
				break;
			default:
				break;
			}
		}

		idx++;
		gnutls_pkcs12_bag_deinit(bag);
		bag = NULL;

		if (privkey_ok != 0)	/* private key was found */
			break;
	}

	if (privkey_ok == 0) {	/* no private key */
		gnutls_assert();
		return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
	}

	/* now find the corresponding certificate 
	 */
	idx = 0;
	bag = NULL;
	for (;;) {
		ret = gnutls_pkcs12_bag_init(&bag);
		if (ret < 0) {
			bag = NULL;
			gnutls_assert();
			goto done;
		}

		ret = gnutls_pkcs12_get_bag(p12, idx, bag);
		if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
			gnutls_pkcs12_bag_deinit(bag);
			bag = NULL;
			break;
		}
		if (ret < 0) {
			gnutls_assert();
			goto done;
		}

		ret = gnutls_pkcs12_bag_get_type(bag, 0);
		if (ret < 0) {
			gnutls_assert();
			goto done;
		}

		if (ret == GNUTLS_BAG_ENCRYPTED) {
			ret = gnutls_pkcs12_bag_decrypt(bag, password);
			if (ret < 0) {
				gnutls_assert();
				goto done;
			}
		}

		elements_in_bag = gnutls_pkcs12_bag_get_count(bag);
		if (elements_in_bag < 0) {
			gnutls_assert();
			goto done;
		}

		for (i = 0; i < (unsigned)elements_in_bag; i++) {
			int type;
			gnutls_datum_t data;
			gnutls_x509_crt_t this_cert;

			type = gnutls_pkcs12_bag_get_type(bag, i);
			if (type < 0) {
				gnutls_assert();
				goto done;
			}

			ret = gnutls_pkcs12_bag_get_data(bag, i, &data);
			if (ret < 0) {
				gnutls_assert();
				goto done;
			}

			switch (type) {
			case GNUTLS_BAG_CERTIFICATE:
				ret = gnutls_x509_crt_init(&this_cert);
				if (ret < 0) {
					gnutls_assert();
					goto done;
				}

				ret =
				    gnutls_x509_crt_import(this_cert,
							   &data,
							   GNUTLS_X509_FMT_DER);
				if (ret < 0) {
					gnutls_assert();
					gnutls_x509_crt_deinit(this_cert);
					this_cert = NULL;
					goto done;
				}

				/* check if the key id match */
				cert_id_size = sizeof(cert_id);
				ret =
				    gnutls_x509_crt_get_key_id(this_cert,
							       0, cert_id,
							       &cert_id_size);
				if (ret < 0) {
					gnutls_assert();
					gnutls_x509_crt_deinit(this_cert);
					this_cert = NULL;
					goto done;
				}

				if (memcmp(cert_id, key_id, cert_id_size) != 0) {	/* they don't match - skip the certificate */
					_extra_certs =
						gnutls_realloc_fast
						(_extra_certs,
						 sizeof(_extra_certs
							[0]) *
						 ++_extra_certs_len);
					if (!_extra_certs) {
						gnutls_assert();
						ret =
							GNUTLS_E_MEMORY_ERROR;
						goto done;
					}
					_extra_certs
						[_extra_certs_len -
						 1] = this_cert;
					this_cert = NULL;
				} else {
					if (chain && _chain_len == 0) {
						_chain =
						    gnutls_malloc(sizeof
								  (_chain
								   [0]) *
								  (++_chain_len));
						if (!_chain) {
							gnutls_assert();
							ret =
							    GNUTLS_E_MEMORY_ERROR;
							goto done;
						}
						_chain[_chain_len - 1] =
						    this_cert;
						this_cert = NULL;
					} else {
						gnutls_x509_crt_deinit
						    (this_cert);
						this_cert = NULL;
					}
				}
				break;

			case GNUTLS_BAG_CRL:
				if (crl == NULL || *crl != NULL) {
					gnutls_assert();
					break;
				}

				ret = gnutls_x509_crl_init(crl);
				if (ret < 0) {
					gnutls_assert();
					goto done;
				}

				ret =
				    gnutls_x509_crl_import(*crl, &data,
							   GNUTLS_X509_FMT_DER);
				if (ret < 0) {
					gnutls_assert();
					gnutls_x509_crl_deinit(*crl);
					*crl = NULL;
					goto done;
				}
				break;

			case GNUTLS_BAG_ENCRYPTED:
				/* XXX Bother to recurse one level down?  Unlikely to
				   use the same password anyway. */
			case GNUTLS_BAG_EMPTY:
			default:
				break;
			}
		}

		idx++;
		gnutls_pkcs12_bag_deinit(bag);
		bag = NULL;
	}

	if (chain != NULL) {
		if (_chain_len != 1) {
			ret = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
			goto done;
		}

		ret =
		    make_chain(&_chain, &_chain_len, &_extra_certs,
			       &_extra_certs_len, flags);
		if (ret < 0) {
			gnutls_assert();
			goto done;
		}
	}

	ret = 0;

      done:
	if (bag)
		gnutls_pkcs12_bag_deinit(bag);

	if (ret < 0) {
		if (*key) {
			gnutls_x509_privkey_deinit(*key);
			*key = NULL;
		}
		if (crl != NULL && *crl != NULL) {
			gnutls_x509_crl_deinit(*crl);
			*crl = NULL;
		}
		if (_extra_certs_len && _extra_certs != NULL) {
			for (i = 0; i < _extra_certs_len; i++)
				gnutls_x509_crt_deinit(_extra_certs[i]);
			gnutls_free(_extra_certs);
		}
		if (_chain_len && _chain != NULL) {
			for (i = 0; i < _chain_len; i++)
				gnutls_x509_crt_deinit(_chain[i]);
			gnutls_free(_chain);
		}

		return ret;
	}

	if (extra_certs && _extra_certs_len > 0) {
		*extra_certs = _extra_certs;
		*extra_certs_len = _extra_certs_len;
	} else {
		if (extra_certs) {
			*extra_certs = NULL;
			*extra_certs_len = 0;
		}
		for (i = 0; i < _extra_certs_len; i++)
			gnutls_x509_crt_deinit(_extra_certs[i]);
		gnutls_free(_extra_certs);
	}

	if (chain != NULL) {
		*chain = _chain;
		*chain_len = _chain_len;
	}

	return ret;
}
Esempio n. 17
0
void doit(void)
{
	gnutls_pkcs12_t pkcs12;
	gnutls_x509_crt_t client;
	gnutls_x509_crt_t ca;
	gnutls_pkcs12_bag_t bag;
	unsigned char key_id_buf[20];
	gnutls_datum_t key_id;
	int ret, indx;
	char outbuf[10240];
	size_t size;
	unsigned tests, i;

	ret = global_init();
	if (ret < 0) {
		fprintf(stderr, "global_init %d", ret);
		exit(1);
	}

	gnutls_global_set_log_function(tls_log_func);
	if (debug)
		gnutls_global_set_log_level(4711);

	/* Read certs. */
	ret = gnutls_x509_crt_init(&client);
	if (ret < 0) {
		fprintf(stderr, "crt_init: %d", ret);
		exit(1);
	}

	ret =
	    gnutls_x509_crt_import(client, &client_dat,
				   GNUTLS_X509_FMT_PEM);
	if (ret < 0) {
		fprintf(stderr, "crt_import: %d", ret);
		exit(1);
	}

	ret = gnutls_x509_crt_init(&ca);
	if (ret < 0) {
		fprintf(stderr, "ca_init: %d", ret);
		exit(1);
	}

	ret = gnutls_x509_crt_import(ca, &ca_dat, GNUTLS_X509_FMT_PEM);
	if (ret < 0) {
		fprintf(stderr, "ca_import: %d", ret);
		exit(1);
	}

	/* Create PKCS#12 structure. */
	ret = gnutls_pkcs12_init(&pkcs12);
	if (ret < 0) {
		fprintf(stderr, "pkcs12_init: %d", ret);
		exit(1);
	}

	/* Generate and add PKCS#12 cert bags. */
#ifndef ENABLE_FIPS140
	tests = 2; /* include RC2 */
#else
	tests = 1;
#endif
	for (i = 0; i < tests; i++) {
		ret = gnutls_pkcs12_bag_init(&bag);
		if (ret < 0) {
			fprintf(stderr, "bag_init: %s (%d)\n", gnutls_strerror(ret), ret);
			exit(1);
		}

		ret = gnutls_pkcs12_bag_set_crt(bag, i == 0 ? client : ca);
		if (ret < 0) {
			fprintf(stderr, "set_crt: %s (%d)\n", gnutls_strerror(ret), ret);
			exit(1);
		}

		indx = ret;

		ret = gnutls_pkcs12_bag_set_friendly_name(bag, indx,
							  i ==
							  0 ? "client" :
							  "ca");
		if (ret < 0) {
			fprintf(stderr, "set_friendly_name: %s (%d)\n", gnutls_strerror(ret), ret);
			exit(1);
		}

		size = sizeof(key_id_buf);
		ret = gnutls_x509_crt_get_key_id(i == 0 ? client : ca, 0,
						 key_id_buf, &size);
		if (ret < 0) {
			fprintf(stderr, "get_key_id: %s (%d)\n", gnutls_strerror(ret), ret);
			exit(1);
		}

		key_id.data = key_id_buf;
		key_id.size = size;

		ret = gnutls_pkcs12_bag_set_key_id(bag, indx, &key_id);
		if (ret < 0) {
			fprintf(stderr, "bag_set_key_id: %s (%d)\n", gnutls_strerror(ret), ret);
			exit(1);
		}

		ret = gnutls_pkcs12_bag_encrypt(bag, "pass",
						i ==
						0 ?
						GNUTLS_PKCS8_USE_PKCS12_3DES
						:
						GNUTLS_PKCS_USE_PKCS12_RC2_40);
		if (ret < 0) {
			fprintf(stderr, "bag_encrypt: %d: %s", ret,
				i == 0 ? "3DES" : "RC2-40");
			exit(1);
		}

		ret = gnutls_pkcs12_set_bag(pkcs12, bag);
		if (ret < 0) {
			fprintf(stderr, "set_bag: %s (%d)\n", gnutls_strerror(ret), ret);
			exit(1);
		}

		gnutls_pkcs12_bag_deinit(bag);
	}

	/* MAC the structure, export and print. */
	ret = gnutls_pkcs12_generate_mac2(pkcs12, GNUTLS_MAC_SHA1, "pass");
	if (ret < 0) {
		fprintf(stderr, "generate_mac: %s (%d)\n", gnutls_strerror(ret), ret);
		exit(1);
	}

	ret = gnutls_pkcs12_verify_mac(pkcs12, "pass");
	if (ret < 0) {
		fprintf(stderr, "verify_mac: %s (%d)\n", gnutls_strerror(ret), ret);
		exit(1);
	}

	ret = gnutls_pkcs12_generate_mac2(pkcs12, GNUTLS_MAC_SHA256, "passwd");
	if (ret < 0) {
		fprintf(stderr, "generate_mac2: %s (%d)\n", gnutls_strerror(ret), ret);
		exit(1);
	}

	ret = gnutls_pkcs12_verify_mac(pkcs12, "passwd");
	if (ret < 0) {
		fprintf(stderr, "verify_mac2: %s (%d)\n", gnutls_strerror(ret), ret);
		exit(1);
	}

	size = sizeof(outbuf);
	ret =
	    gnutls_pkcs12_export(pkcs12, GNUTLS_X509_FMT_PEM, outbuf,
				 &size);
	if (ret < 0) {
		fprintf(stderr, "pkcs12_export: %s (%d)\n", gnutls_strerror(ret), ret);
		exit(1);
	}

	if (debug)
		fwrite(outbuf, size, 1, stdout);

	/* Cleanup. */
	gnutls_pkcs12_deinit(pkcs12);
	gnutls_x509_crt_deinit(client);
	gnutls_x509_crt_deinit(ca);
	gnutls_global_deinit();
}
static int				/* O - 1 on success, 0 on failure */
make_certificate(cupsd_client_t *con)	/* I - Client connection */
{
  gnutls_x509_crt	crt;		/* Self-signed certificate */
  gnutls_x509_privkey	key;		/* Encryption key */
  cups_lang_t		*language;	/* Default language info */
  cups_file_t		*fp;		/* Key/cert file */
  unsigned char		buffer[8192];	/* Buffer for x509 data */
  size_t		bytes;		/* Number of bytes of data */
  unsigned char		serial[4];	/* Serial number buffer */
  time_t		curtime;	/* Current time */
  int			result;		/* Result of GNU TLS calls */


 /*
  * Create the encryption key...
  */

  cupsdLogMessage(CUPSD_LOG_INFO, "Generating SSL server key...");

  gnutls_x509_privkey_init(&key);
  gnutls_x509_privkey_generate(key, GNUTLS_PK_RSA, 2048, 0);

 /*
  * Save it...
  */

  bytes = sizeof(buffer);

  if ((result = gnutls_x509_privkey_export(key, GNUTLS_X509_FMT_PEM,
                                           buffer, &bytes)) < 0)
  {
    cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to export SSL server key - %s",
                    gnutls_strerror(result));
    gnutls_x509_privkey_deinit(key);
    return (0);
  }
  else if ((fp = cupsFileOpen(ServerKey, "w")) != NULL)
  {
    cupsFileWrite(fp, (char *)buffer, bytes);
    cupsFileClose(fp);

    cupsdLogMessage(CUPSD_LOG_INFO, "Created SSL server key file \"%s\"...",
		    ServerKey);
  }
  else
  {
    cupsdLogMessage(CUPSD_LOG_ERROR,
                    "Unable to create SSL server key file \"%s\" - %s",
		    ServerKey, strerror(errno));
    gnutls_x509_privkey_deinit(key);
    return (0);
  }

 /*
  * Create the self-signed certificate...
  */

  cupsdLogMessage(CUPSD_LOG_INFO, "Generating self-signed SSL certificate...");

  language  = cupsLangDefault();
  curtime   = time(NULL);
  serial[0] = curtime >> 24;
  serial[1] = curtime >> 16;
  serial[2] = curtime >> 8;
  serial[3] = curtime;

  gnutls_x509_crt_init(&crt);
  if (strlen(language->language) == 5)
    gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COUNTRY_NAME, 0,
                                  language->language + 3, 2);
  else
    gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COUNTRY_NAME, 0,
                                  "US", 2);
  gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COMMON_NAME, 0,
                                ServerName, strlen(ServerName));
  gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_ORGANIZATION_NAME, 0,
                                ServerName, strlen(ServerName));
  gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME,
                                0, "Unknown", 7);
  gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME, 0,
                                "Unknown", 7);
  gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_LOCALITY_NAME, 0,
                                "Unknown", 7);
  gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_PKCS9_EMAIL, 0,
                                ServerAdmin, strlen(ServerAdmin));
  gnutls_x509_crt_set_key(crt, key);
  gnutls_x509_crt_set_serial(crt, serial, sizeof(serial));
  gnutls_x509_crt_set_activation_time(crt, curtime);
  gnutls_x509_crt_set_expiration_time(crt, curtime + 10 * 365 * 86400);
  gnutls_x509_crt_set_ca_status(crt, 0);
  gnutls_x509_crt_set_subject_alternative_name(crt, GNUTLS_SAN_DNSNAME,
                                               ServerName);
  gnutls_x509_crt_set_key_purpose_oid(crt, GNUTLS_KP_TLS_WWW_SERVER, 0);
  gnutls_x509_crt_set_key_usage(crt, GNUTLS_KEY_KEY_ENCIPHERMENT);
  gnutls_x509_crt_set_version(crt, 3);

  bytes = sizeof(buffer);
  if (gnutls_x509_crt_get_key_id(crt, 0, buffer, &bytes) >= 0)
    gnutls_x509_crt_set_subject_key_id(crt, buffer, bytes);

  gnutls_x509_crt_sign(crt, crt, key);

 /*
  * Save it...
  */

  bytes = sizeof(buffer);
  if ((result = gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_PEM,
                                       buffer, &bytes)) < 0)
    cupsdLogMessage(CUPSD_LOG_ERROR,
                    "Unable to export SSL server certificate - %s",
		    gnutls_strerror(result));
  else if ((fp = cupsFileOpen(ServerCertificate, "w")) != NULL)
  {
    cupsFileWrite(fp, (char *)buffer, bytes);
    cupsFileClose(fp);

    cupsdLogMessage(CUPSD_LOG_INFO,
                    "Created SSL server certificate file \"%s\"...",
		    ServerCertificate);
  }
  else
    cupsdLogMessage(CUPSD_LOG_ERROR,
                    "Unable to create SSL server certificate file \"%s\" - %s",
		    ServerCertificate, strerror(errno));

 /*
  * Cleanup...
  */

  gnutls_x509_crt_deinit(crt);
  gnutls_x509_privkey_deinit(key);

  return (1);
}