Beispiel #1
0
static int
add_one_attribute(Attribute **attr,
		  unsigned int *len,
		  const heim_oid *oid,
		  heim_octet_string *data)
{
    void *d;
    int ret;

    d = realloc(*attr, sizeof((*attr)[0]) * (*len + 1));
    if (d == NULL)
	return ENOMEM;
    (*attr) = d;

    ret = der_copy_oid(oid, &(*attr)[*len].type);
    if (ret)
	return ret;

    ALLOC_SEQ(&(*attr)[*len].value, 1);
    if ((*attr)[*len].value.val == NULL) {
	der_free_oid(&(*attr)[*len].type);
	return ENOMEM;
    }

    (*attr)[*len].value.val[0].data = data->data;
    (*attr)[*len].value.val[0].length = data->length;

    *len += 1;

    return 0;
}
Beispiel #2
0
int
hx509_ca_tbs_add_eku(hx509_context context,
		     hx509_ca_tbs tbs,
		     const heim_oid *oid)
{
    void *ptr;
    int ret;
    unsigned i;

    /* search for duplicates */
    for (i = 0; i < tbs->eku.len; i++) {
	if (der_heim_oid_cmp(oid, &tbs->eku.val[i]) == 0)
	    return 0;
    }

    ptr = realloc(tbs->eku.val, sizeof(tbs->eku.val[0]) * (tbs->eku.len + 1));
    if (ptr == NULL) {
	hx509_set_error_string(context, 0, ENOMEM, "out of memory");
	return ENOMEM;
    }
    tbs->eku.val = ptr;
    ret = der_copy_oid(oid, &tbs->eku.val[tbs->eku.len]);
    if (ret) {
	hx509_set_error_string(context, 0, ret, "out of memory");
	return ret;
    }
    tbs->eku.len += 1;
    return 0;
}
Beispiel #3
0
int
_hx509_name_modify(hx509_context context,
		   Name *name, 
		   int append,
		   const heim_oid *oid, 
		   const char *str)
{
    RelativeDistinguishedName *rdn;
    int ret;
    void *ptr;

    ptr = realloc(name->u.rdnSequence.val, 
		  sizeof(name->u.rdnSequence.val[0]) * 
		  (name->u.rdnSequence.len + 1));
    if (ptr == NULL) {
	hx509_set_error_string(context, 0, ENOMEM, "Out of memory");
	return ENOMEM;
    }
    name->u.rdnSequence.val = ptr;

    if (append) {
	rdn = &name->u.rdnSequence.val[name->u.rdnSequence.len];
    } else {
	memmove(&name->u.rdnSequence.val[1],
		&name->u.rdnSequence.val[0],
		name->u.rdnSequence.len * 
		sizeof(name->u.rdnSequence.val[0]));
	
	rdn = &name->u.rdnSequence.val[0];
    }
    rdn->val = malloc(sizeof(rdn->val[0]));
    if (rdn->val == NULL)
	return ENOMEM;
    rdn->len = 1;
    ret = der_copy_oid(oid, &rdn->val[0].type);
    if (ret)
	return ret;
    rdn->val[0].value.element = choice_DirectoryString_utf8String;
    rdn->val[0].value.u.utf8String = strdup(str);
    if (rdn->val[0].value.u.utf8String == NULL)
	return ENOMEM;
    name->u.rdnSequence.len += 1;

    return 0;
}
Beispiel #4
0
static int
add_extension(hx509_context context,
	      TBSCertificate *tbsc,
	      int critical_flag,
	      const heim_oid *oid,
	      const heim_octet_string *data)
{
    Extension ext;
    int ret;

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

    if (critical_flag) {
	ext.critical = malloc(sizeof(*ext.critical));
	if (ext.critical == NULL) {
	    ret = ENOMEM;
	    hx509_set_error_string(context, 0, ret, "Out of memory");
	    goto out;
	}
	*ext.critical = TRUE;
    }

    ret = der_copy_oid(oid, &ext.extnID);
    if (ret) {
	hx509_set_error_string(context, 0, ret, "Out of memory");
	goto out;
    }
    ret = der_copy_octet_string(data, &ext.extnValue);
    if (ret) {
	hx509_set_error_string(context, 0, ret, "Out of memory");
	goto out;
    }
    ret = add_Extensions(tbsc->extensions, &ext);
    if (ret) {
	hx509_set_error_string(context, 0, ret, "Out of memory");
	goto out;
    }
out:
    free_Extension(&ext);
    return ret;
}
Beispiel #5
0
static int
stringtooid(const char *name, size_t len, heim_oid *oid)
{
    int i, ret;
    char *s;
    
    memset(oid, 0, sizeof(*oid));

    for (i = 0; i < sizeof(no)/sizeof(no[0]); i++) {
	if (strncasecmp(no[i].n, name, len) == 0)
	    return der_copy_oid((*no[i].o)(), oid);
    }
    s = malloc(len + 1);
    if (s == NULL)
	return ENOMEM;
    memcpy(s, name, len);
    s[len] = '\0';
    ret = der_parse_heim_oid(s, ".", oid);
    free(s);
    return ret;
}
Beispiel #6
0
int
_hx509_request_add_eku(hx509_context context,
		       hx509_request req,
		       const heim_oid *oid)
{
    void *val;
    int ret;

    val = realloc(req->eku.val, sizeof(req->eku.val[0]) * (req->eku.len + 1));
    if (val == NULL)
	return ENOMEM;
    req->eku.val = val;

    ret = der_copy_oid(oid, &req->eku.val[req->eku.len]);
    if (ret)
	return ret;

    req->eku.len += 1;

    return 0;
}
Beispiel #7
0
int
hx509_cms_unwrap_ContentInfo(const heim_octet_string *in,
			     heim_oid *oid,
			     heim_octet_string *out,
			     int *have_data)
{
    ContentInfo ci;
    size_t size;
    int ret;

    memset(oid, 0, sizeof(*oid));
    memset(out, 0, sizeof(*out));

    ret = decode_ContentInfo(in->data, in->length, &ci, &size);
    if (ret)
	return ret;

    ret = der_copy_oid(&ci.contentType, oid);
    if (ret) {
	free_ContentInfo(&ci);
	return ret;
    }
    if (ci.content) {
	ret = der_copy_octet_string(ci.content, out);
	if (ret) {
	    der_free_oid(oid);
	    free_ContentInfo(&ci);
	    return ret;
	}
    } else
	memset(out, 0, sizeof(*out));

    if (have_data)
	*have_data = (ci.content != NULL) ? 1 : 0;

    free_ContentInfo(&ci);

    return 0;
}
Beispiel #8
0
int
hx509_cms_wrap_ContentInfo(const heim_oid *oid,
			   const heim_octet_string *buf,
			   heim_octet_string *res)
{
    ContentInfo ci;
    size_t size;
    int ret;

    memset(res, 0, sizeof(*res));
    memset(&ci, 0, sizeof(ci));

    ret = der_copy_oid(oid, &ci.contentType);
    if (ret)
	return ret;
    if (buf) {
	ALLOC(ci.content, 1);
	if (ci.content == NULL) {
	    free_ContentInfo(&ci);
	    return ENOMEM;
	}
	ci.content->data = malloc(buf->length);
	if (ci.content->data == NULL) {
	    free_ContentInfo(&ci);
	    return ENOMEM;
	}
	memcpy(ci.content->data, buf->data, buf->length);
	ci.content->length = buf->length;
    }

    ASN1_MALLOC_ENCODE(ContentInfo, res->data, res->length, &ci, &size, ret);
    free_ContentInfo(&ci);
    if (ret)
	return ret;
    if (res->length != size)
	_hx509_abort("internal ASN.1 encoder error");

    return 0;
}
Beispiel #9
0
static int
addBag(hx509_context context,
       PKCS12_AuthenticatedSafe *as,
       const heim_oid *oid,
       void *data,
       size_t length)
{
    void *ptr;
    int ret;

    ptr = realloc(as->val, sizeof(as->val[0]) * (as->len + 1));
    if (ptr == NULL) {
	hx509_set_error_string(context, 0, ENOMEM, "out of memory");
	return ENOMEM;
    }
    as->val = ptr;

    ret = der_copy_oid(oid, &as->val[as->len].contentType);
    if (ret) {
	hx509_set_error_string(context, 0, ret, "out of memory");
	return ret;
    }

    as->val[as->len].content = calloc(1, sizeof(*as->val[0].content));
    if (as->val[as->len].content == NULL) {
	der_free_oid(&as->val[as->len].contentType);
	hx509_set_error_string(context, 0, ENOMEM, "malloc out of memory");
	return ENOMEM;
    }

    as->val[as->len].content->data = data;
    as->val[as->len].content->length = length;

    as->len++;

    return 0;
}
Beispiel #10
0
int
hx509_cms_verify_signed(hx509_context context,
			hx509_verify_ctx ctx,
			unsigned int flags,
			const void *data,
			size_t length,
			const heim_octet_string *signedContent,
			hx509_certs pool,
			heim_oid *contentType,
			heim_octet_string *content,
			hx509_certs *signer_certs)
{
    SignerInfo *signer_info;
    hx509_cert cert = NULL;
    hx509_certs certs = NULL;
    SignedData sd;
    size_t size;
    int ret, found_valid_sig;
    size_t i;

    *signer_certs = NULL;
    content->data = NULL;
    content->length = 0;
    contentType->length = 0;
    contentType->components = NULL;

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

    ret = decode_SignedData(data, length, &sd, &size);
    if (ret) {
	hx509_set_error_string(context, 0, ret,
			       "Failed to decode SignedData");
	goto out;
    }

    if (sd.encapContentInfo.eContent == NULL && signedContent == NULL) {
	ret = HX509_CMS_NO_DATA_AVAILABLE;
	hx509_set_error_string(context, 0, ret,
			       "No content data in SignedData");
	goto out;
    }
    if (sd.encapContentInfo.eContent && signedContent) {
	ret = HX509_CMS_NO_DATA_AVAILABLE;
	hx509_set_error_string(context, 0, ret,
			       "Both external and internal SignedData");
	goto out;
    }

    if (sd.encapContentInfo.eContent)
	ret = der_copy_octet_string(sd.encapContentInfo.eContent, content);
    else
	ret = der_copy_octet_string(signedContent, content);
    if (ret) {
	hx509_set_error_string(context, 0, ret, "malloc: out of memory");
	goto out;
    }

    ret = hx509_certs_init(context, "MEMORY:cms-cert-buffer",
			   0, NULL, &certs);
    if (ret)
	goto out;

    ret = hx509_certs_init(context, "MEMORY:cms-signer-certs",
			   0, NULL, signer_certs);
    if (ret)
	goto out;

    /* XXX Check CMS version */

    ret = any_to_certs(context, &sd, certs);
    if (ret)
	goto out;

    if (pool) {
	ret = hx509_certs_merge(context, certs, pool);
	if (ret)
	    goto out;
    }

    for (found_valid_sig = 0, i = 0; i < sd.signerInfos.len; i++) {
	heim_octet_string signed_data;
	const heim_oid *match_oid;
	heim_oid decode_oid;

	signer_info = &sd.signerInfos.val[i];
	match_oid = NULL;

	if (signer_info->signature.length == 0) {
	    ret = HX509_CMS_MISSING_SIGNER_DATA;
	    hx509_set_error_string(context, 0, ret,
				   "SignerInfo %d in SignedData "
				   "missing sigature", i);
	    continue;
	}

	ret = find_CMSIdentifier(context, &signer_info->sid, certs,
				 _hx509_verify_get_time(ctx), &cert,
				 HX509_QUERY_KU_DIGITALSIGNATURE);
	if (ret) {
	    /**
	     * If HX509_CMS_VS_NO_KU_CHECK is set, allow more liberal
	     * search for matching certificates by not considering
	     * KeyUsage bits on the certificates.
	     */
	    if ((flags & HX509_CMS_VS_NO_KU_CHECK) == 0)
		continue;

	    ret = find_CMSIdentifier(context, &signer_info->sid, certs,
				     _hx509_verify_get_time(ctx), &cert,
				     0);
	    if (ret)
		continue;

	}

	if (signer_info->signedAttrs) {
	    const Attribute *attr;

	    CMSAttributes sa;
	    heim_octet_string os;

	    sa.val = signer_info->signedAttrs->val;
	    sa.len = signer_info->signedAttrs->len;

	    /* verify that sigature exists */
	    attr = find_attribute(&sa, &asn1_oid_id_pkcs9_messageDigest);
	    if (attr == NULL) {
		ret = HX509_CRYPTO_SIGNATURE_MISSING;
		hx509_set_error_string(context, 0, ret,
				       "SignerInfo have signed attributes "
				       "but messageDigest (signature) "
				       "is missing");
		goto next_sigature;
	    }
	    if (attr->value.len != 1) {
		ret = HX509_CRYPTO_SIGNATURE_MISSING;
		hx509_set_error_string(context, 0, ret,
				       "SignerInfo have more then one "
				       "messageDigest (signature)");
		goto next_sigature;
	    }

	    ret = decode_MessageDigest(attr->value.val[0].data,
				       attr->value.val[0].length,
				       &os,
				       &size);
	    if (ret) {
		hx509_set_error_string(context, 0, ret,
				       "Failed to decode "
				       "messageDigest (signature)");
		goto next_sigature;
	    }

	    ret = _hx509_verify_signature(context,
					  NULL,
					  &signer_info->digestAlgorithm,
					  content,
					  &os);
	    der_free_octet_string(&os);
	    if (ret) {
		hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
				       "Failed to verify messageDigest");
		goto next_sigature;
	    }

	    /*
	     * Fetch content oid inside signedAttrs or set it to
	     * id-pkcs7-data.
	     */
	    attr = find_attribute(&sa, &asn1_oid_id_pkcs9_contentType);
	    if (attr == NULL) {
		match_oid = &asn1_oid_id_pkcs7_data;
	    } else {
		if (attr->value.len != 1) {
		    ret = HX509_CMS_DATA_OID_MISMATCH;
		    hx509_set_error_string(context, 0, ret,
					   "More then one oid in signedAttrs");
		    goto next_sigature;

		}
		ret = decode_ContentType(attr->value.val[0].data,
					 attr->value.val[0].length,
					 &decode_oid,
					 &size);
		if (ret) {
		    hx509_set_error_string(context, 0, ret,
					   "Failed to decode "
					   "oid in signedAttrs");
		    goto next_sigature;
		}
		match_oid = &decode_oid;
	    }

	    ASN1_MALLOC_ENCODE(CMSAttributes,
			       signed_data.data,
			       signed_data.length,
			       &sa,
			       &size, ret);
	    if (ret) {
		if (match_oid == &decode_oid)
		    der_free_oid(&decode_oid);
		hx509_clear_error_string(context);
		goto next_sigature;
	    }
	    if (size != signed_data.length)
		_hx509_abort("internal ASN.1 encoder error");

	} else {
	    signed_data.data = content->data;
	    signed_data.length = content->length;
	    match_oid = &asn1_oid_id_pkcs7_data;
	}

	/**
	 * If HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH, allow
	 * encapContentInfo mismatch with the oid in signedAttributes
	 * (or if no signedAttributes where use, pkcs7-data oid).
	 * This is only needed to work with broken CMS implementations
	 * that doesn't follow CMS signedAttributes rules.
	 */

	if (der_heim_oid_cmp(match_oid, &sd.encapContentInfo.eContentType) &&
	    (flags & HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH) == 0) {
	    ret = HX509_CMS_DATA_OID_MISMATCH;
	    hx509_set_error_string(context, 0, ret,
				   "Oid in message mismatch from the expected");
	}
	if (match_oid == &decode_oid)
	    der_free_oid(&decode_oid);

	if (ret == 0) {
	    ret = hx509_verify_signature(context,
					 cert,
					 &signer_info->signatureAlgorithm,
					 &signed_data,
					 &signer_info->signature);
	    if (ret)
		hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
				       "Failed to verify signature in "
				       "CMS SignedData");
	}
        if (signer_info->signedAttrs)
	    free(signed_data.data);
	if (ret)
	    goto next_sigature;

	/**
	 * If HX509_CMS_VS_NO_VALIDATE flags is set, do not verify the
	 * signing certificates and leave that up to the caller.
	 */

	if ((flags & HX509_CMS_VS_NO_VALIDATE) == 0) {
	    ret = hx509_verify_path(context, ctx, cert, certs);
	    if (ret)
		goto next_sigature;
	}

	ret = hx509_certs_add(context, *signer_certs, cert);
	if (ret)
	    goto next_sigature;

	found_valid_sig++;

    next_sigature:
	if (cert)
	    hx509_cert_free(cert);
	cert = NULL;
    }
    /**
     * If HX509_CMS_VS_ALLOW_ZERO_SIGNER is set, allow empty
     * SignerInfo (no signatures). If SignedData have no signatures,
     * the function will return 0 with signer_certs set to NULL. Zero
     * signers is allowed by the standard, but since its only useful
     * in corner cases, it make into a flag that the caller have to
     * turn on.
     */
    if (sd.signerInfos.len == 0 && (flags & HX509_CMS_VS_ALLOW_ZERO_SIGNER)) {
	if (*signer_certs)
	    hx509_certs_free(signer_certs);
    } else if (found_valid_sig == 0) {
	if (ret == 0) {
	    ret = HX509_CMS_SIGNER_NOT_FOUND;
	    hx509_set_error_string(context, 0, ret,
				   "No signers where found");
	}
	goto out;
    }

    ret = der_copy_oid(&sd.encapContentInfo.eContentType, contentType);
    if (ret) {
	hx509_clear_error_string(context);
	goto out;
    }

out:
    free_SignedData(&sd);
    if (certs)
	hx509_certs_free(&certs);
    if (ret) {
	if (content->data)
	    der_free_octet_string(content);
	if (*signer_certs)
	    hx509_certs_free(signer_certs);
	der_free_oid(contentType);
	der_free_octet_string(content);
    }

    return ret;
}
Beispiel #11
0
int
hx509_cms_envelope_1(hx509_context context,
		     int flags,
		     hx509_cert cert,
		     const void *data,
		     size_t length,
		     const heim_oid *encryption_type,
		     const heim_oid *contentType,
		     heim_octet_string *content)
{
    KeyTransRecipientInfo *ri;
    heim_octet_string ivec;
    heim_octet_string key;
    hx509_crypto crypto = NULL;
    int ret, cmsidflag;
    EnvelopedData ed;
    size_t size;

    memset(&ivec, 0, sizeof(ivec));
    memset(&key, 0, sizeof(key));
    memset(&ed, 0, sizeof(ed));
    memset(content, 0, sizeof(*content));

    if (encryption_type == NULL)
	encryption_type = &asn1_oid_id_aes_256_cbc;

    if ((flags & HX509_CMS_EV_NO_KU_CHECK) == 0) {
	ret = _hx509_check_key_usage(context, cert, 1 << 2, TRUE);
	if (ret)
	    goto out;
    }

    ret = hx509_crypto_init(context, NULL, encryption_type, &crypto);
    if (ret)
	goto out;

    if (flags & HX509_CMS_EV_ALLOW_WEAK)
	hx509_crypto_allow_weak(crypto);

    ret = hx509_crypto_set_random_key(crypto, &key);
    if (ret) {
	hx509_set_error_string(context, 0, ret,
			       "Create random key for EnvelopedData content");
	goto out;
    }

    ret = hx509_crypto_random_iv(crypto, &ivec);
    if (ret) {
	hx509_set_error_string(context, 0, ret,
			       "Failed to create a random iv");
	goto out;
    }

    ret = hx509_crypto_encrypt(crypto,
			       data,
			       length,
			       &ivec,
			       &ed.encryptedContentInfo.encryptedContent);
    if (ret) {
	hx509_set_error_string(context, 0, ret,
			       "Failed to encrypt EnvelopedData content");
	goto out;
    }

    {
	AlgorithmIdentifier *enc_alg;
	enc_alg = &ed.encryptedContentInfo.contentEncryptionAlgorithm;
	ret = der_copy_oid(encryption_type, &enc_alg->algorithm);
	if (ret) {
	    hx509_set_error_string(context, 0, ret,
				   "Failed to set crypto oid "
				   "for EnvelopedData");
	    goto out;
	}
	ALLOC(enc_alg->parameters, 1);
	if (enc_alg->parameters == NULL) {
	    ret = ENOMEM;
	    hx509_set_error_string(context, 0, ret,
				   "Failed to allocate crypto paramaters "
				   "for EnvelopedData");
	    goto out;
	}

	ret = hx509_crypto_get_params(context,
				      crypto,
				      &ivec,
				      enc_alg->parameters);
	if (ret) {
	    goto out;
	}
    }

    ALLOC_SEQ(&ed.recipientInfos, 1);
    if (ed.recipientInfos.val == NULL) {
	ret = ENOMEM;
	hx509_set_error_string(context, 0, ret,
			       "Failed to allocate recipients info "
			       "for EnvelopedData");
	goto out;
    }

    ri = &ed.recipientInfos.val[0];

    if (flags & HX509_CMS_EV_ID_NAME) {
	ri->version = 0;
	cmsidflag = CMS_ID_NAME;
    } else {
	ri->version = 2;
	cmsidflag = CMS_ID_SKI;
    }

    ret = fill_CMSIdentifier(cert, cmsidflag, &ri->rid);
    if (ret) {
	hx509_set_error_string(context, 0, ret,
			       "Failed to set CMS identifier info "
			       "for EnvelopedData");
	goto out;
    }

    ret = hx509_cert_public_encrypt(context,
				     &key, cert,
				     &ri->keyEncryptionAlgorithm.algorithm,
				     &ri->encryptedKey);
    if (ret) {
	hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
			       "Failed to encrypt transport key for "
			       "EnvelopedData");
	goto out;
    }

    /*
     *
     */

    ed.version = 0;
    ed.originatorInfo = NULL;

    ret = der_copy_oid(contentType, &ed.encryptedContentInfo.contentType);
    if (ret) {
	hx509_set_error_string(context, 0, ret,
			       "Failed to copy content oid for "
			       "EnvelopedData");
	goto out;
    }

    ed.unprotectedAttrs = NULL;

    ASN1_MALLOC_ENCODE(EnvelopedData, content->data, content->length,
		       &ed, &size, ret);
    if (ret) {
	hx509_set_error_string(context, 0, ret,
			       "Failed to encode EnvelopedData");
	goto out;
    }
    if (size != content->length)
	_hx509_abort("internal ASN.1 encoder error");

out:
    if (crypto)
	hx509_crypto_destroy(crypto);
    if (ret)
	der_free_octet_string(content);
    der_free_octet_string(&key);
    der_free_octet_string(&ivec);
    free_EnvelopedData(&ed);

    return ret;
}
Beispiel #12
0
int
hx509_cms_unenvelope(hx509_context context,
		     hx509_certs certs,
		     int flags,
		     const void *data,
		     size_t length,
		     const heim_octet_string *encryptedContent,
		     time_t time_now,
		     heim_oid *contentType,
		     heim_octet_string *content)
{
    heim_octet_string key;
    EnvelopedData ed;
    hx509_cert cert;
    AlgorithmIdentifier *ai;
    const heim_octet_string *enccontent;
    heim_octet_string *params, params_data;
    heim_octet_string ivec;
    size_t size;
    int ret, matched = 0, findflags = 0;
    size_t i;


    memset(&key, 0, sizeof(key));
    memset(&ed, 0, sizeof(ed));
    memset(&ivec, 0, sizeof(ivec));
    memset(content, 0, sizeof(*content));
    memset(contentType, 0, sizeof(*contentType));

    if ((flags & HX509_CMS_UE_DONT_REQUIRE_KU_ENCIPHERMENT) == 0)
	findflags |= HX509_QUERY_KU_ENCIPHERMENT;

    ret = decode_EnvelopedData(data, length, &ed, &size);
    if (ret) {
	hx509_set_error_string(context, 0, ret,
			       "Failed to decode EnvelopedData");
	return ret;
    }

    if (ed.recipientInfos.len == 0) {
	ret = HX509_CMS_NO_RECIPIENT_CERTIFICATE;
	hx509_set_error_string(context, 0, ret,
			       "No recipient info in enveloped data");
	goto out;
    }

    enccontent = ed.encryptedContentInfo.encryptedContent;
    if (enccontent == NULL) {
	if (encryptedContent == NULL) {
	    ret = HX509_CMS_NO_DATA_AVAILABLE;
	    hx509_set_error_string(context, 0, ret,
				   "Content missing from encrypted data");
	    goto out;
	}
	enccontent = encryptedContent;
    } else if (encryptedContent != NULL) {
	ret = HX509_CMS_NO_DATA_AVAILABLE;
	hx509_set_error_string(context, 0, ret,
			       "Both internal and external encrypted data");
	goto out;
    }

    cert = NULL;
    for (i = 0; i < ed.recipientInfos.len; i++) {
	KeyTransRecipientInfo *ri;
	char *str;
	int ret2;

	ri = &ed.recipientInfos.val[i];

	ret = find_CMSIdentifier(context, &ri->rid, certs,
				 time_now, &cert,
				 HX509_QUERY_PRIVATE_KEY|findflags);
	if (ret)
	    continue;

	matched = 1; /* found a matching certificate, let decrypt */

	ret = _hx509_cert_private_decrypt(context,
					  &ri->encryptedKey,
					  &ri->keyEncryptionAlgorithm.algorithm,
					  cert, &key);

	hx509_cert_free(cert);
	if (ret == 0)
	    break; /* succuessfully decrypted cert */
	cert = NULL;
	ret2 = unparse_CMSIdentifier(context, &ri->rid, &str);
	if (ret2 == 0) {
	    hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
				   "Failed to decrypt with %s", str);
	    free(str);
	}
    }

    if (!matched) {
	ret = HX509_CMS_NO_RECIPIENT_CERTIFICATE;
	hx509_set_error_string(context, 0, ret,
			       "No private key matched any certificate");
	goto out;
    }

    if (cert == NULL) {
	ret = HX509_CMS_NO_RECIPIENT_CERTIFICATE;
	hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
			       "No private key decrypted the transfer key");
	goto out;
    }

    ret = der_copy_oid(&ed.encryptedContentInfo.contentType, contentType);
    if (ret) {
	hx509_set_error_string(context, 0, ret,
			       "Failed to copy EnvelopedData content oid");
	goto out;
    }

    ai = &ed.encryptedContentInfo.contentEncryptionAlgorithm;
    if (ai->parameters) {
	params_data.data = ai->parameters->data;
	params_data.length = ai->parameters->length;
	params = &params_data;
    } else
	params = NULL;

    {
	hx509_crypto crypto;

	ret = hx509_crypto_init(context, NULL, &ai->algorithm, &crypto);
	if (ret)
	    goto out;

	if (flags & HX509_CMS_UE_ALLOW_WEAK)
	    hx509_crypto_allow_weak(crypto);

	if (params) {
	    ret = hx509_crypto_set_params(context, crypto, params, &ivec);
	    if (ret) {
		hx509_crypto_destroy(crypto);
		goto out;
	    }
	}

	ret = hx509_crypto_set_key_data(crypto, key.data, key.length);
	if (ret) {
	    hx509_crypto_destroy(crypto);
	    hx509_set_error_string(context, 0, ret,
				   "Failed to set key for decryption "
				   "of EnvelopedData");
	    goto out;
	}

	ret = hx509_crypto_decrypt(crypto,
				   enccontent->data,
				   enccontent->length,
				   ivec.length ? &ivec : NULL,
				   content);
	hx509_crypto_destroy(crypto);
	if (ret) {
	    hx509_set_error_string(context, 0, ret,
				   "Failed to decrypt EnvelopedData");
	    goto out;
	}
    }

out:

    free_EnvelopedData(&ed);
    der_free_octet_string(&key);
    if (ivec.length)
	der_free_octet_string(&ivec);
    if (ret) {
	der_free_oid(contentType);
	der_free_octet_string(content);
    }

    return ret;
}
Beispiel #13
0
int
hx509_cms_decrypt_encrypted(hx509_context context,
			    hx509_lock lock,
			    const void *data,
			    size_t length,
			    heim_oid *contentType,
			    heim_octet_string *content)
{
    heim_octet_string cont;
    CMSEncryptedData ed;
    AlgorithmIdentifier *ai;
    int ret;

    memset(content, 0, sizeof(*content));
    memset(&cont, 0, sizeof(cont));

    ret = decode_CMSEncryptedData(data, length, &ed, NULL);
    if (ret) {
	hx509_set_error_string(context, 0, ret,
			       "Failed to decode CMSEncryptedData");
	return ret;
    }

    if (ed.encryptedContentInfo.encryptedContent == NULL) {
	ret = HX509_CMS_NO_DATA_AVAILABLE;
	hx509_set_error_string(context, 0, ret,
			       "No content in EncryptedData");
	goto out;
    }

    ret = der_copy_oid(&ed.encryptedContentInfo.contentType, contentType);
    if (ret) {
	hx509_clear_error_string(context);
	goto out;
    }

    ai = &ed.encryptedContentInfo.contentEncryptionAlgorithm;
    if (ai->parameters == NULL) {
	ret = HX509_ALG_NOT_SUPP;
	hx509_clear_error_string(context);
	goto out;
    }

    ret = _hx509_pbe_decrypt(context,
			     lock,
			     ai,
			     ed.encryptedContentInfo.encryptedContent,
			     &cont);
    if (ret)
	goto out;

    *content = cont;

out:
    if (ret) {
	if (cont.data)
	    free(cont.data);
    }
    free_CMSEncryptedData(&ed);
    return ret;
}
Beispiel #14
0
int
hx509_cms_create_signed(hx509_context context,
			int flags,
			const heim_oid *eContentType,
			const void *data, size_t length,
			const AlgorithmIdentifier *digest_alg,
			hx509_certs certs,
			hx509_peer_info peer,
			hx509_certs anchors,
			hx509_certs pool,
			heim_octet_string *signed_data)
{
    unsigned int i, j;
    hx509_name name;
    int ret;
    size_t size;
    struct sigctx sigctx;

    memset(&sigctx, 0, sizeof(sigctx));
    memset(&name, 0, sizeof(name));

    if (eContentType == NULL)
	eContentType = &asn1_oid_id_pkcs7_data;

    sigctx.digest_alg = digest_alg;
    sigctx.content.data = rk_UNCONST(data);
    sigctx.content.length = length;
    sigctx.eContentType = eContentType;
    sigctx.peer = peer;
    /**
     * Use HX509_CMS_SIGNATURE_ID_NAME to preferred use of issuer name
     * and serial number if possible. Otherwise subject key identifier
     * will preferred.
     */
    if (flags & HX509_CMS_SIGNATURE_ID_NAME)
	sigctx.cmsidflag = CMS_ID_NAME;
    else
	sigctx.cmsidflag = CMS_ID_SKI;

    /**
     * Use HX509_CMS_SIGNATURE_LEAF_ONLY to only request leaf
     * certificates to be added to the SignedData.
     */
    sigctx.leafonly = (flags & HX509_CMS_SIGNATURE_LEAF_ONLY) ? 1 : 0;

    /**
     * Use HX509_CMS_NO_CERTS to make the SignedData contain no
     * certificates, overrides HX509_CMS_SIGNATURE_LEAF_ONLY.
     */

    if ((flags & HX509_CMS_SIGNATURE_NO_CERTS) == 0) {
	ret = hx509_certs_init(context, "MEMORY:certs", 0, NULL, &sigctx.certs);
	if (ret)
	    return ret;
    }

    sigctx.anchors = anchors;
    sigctx.pool = pool;

    sigctx.sd.version = CMSVersion_v3;

    der_copy_oid(eContentType, &sigctx.sd.encapContentInfo.eContentType);

    /**
     * Use HX509_CMS_SIGNATURE_DETACHED to create detached signatures.
     */
    if ((flags & HX509_CMS_SIGNATURE_DETACHED) == 0) {
	ALLOC(sigctx.sd.encapContentInfo.eContent, 1);
	if (sigctx.sd.encapContentInfo.eContent == NULL) {
	    hx509_clear_error_string(context);
	    ret = ENOMEM;
	    goto out;
	}

	sigctx.sd.encapContentInfo.eContent->data = malloc(length);
	if (sigctx.sd.encapContentInfo.eContent->data == NULL) {
	    hx509_clear_error_string(context);
	    ret = ENOMEM;
	    goto out;
	}
	memcpy(sigctx.sd.encapContentInfo.eContent->data, data, length);
	sigctx.sd.encapContentInfo.eContent->length = length;
    }

    /**
     * Use HX509_CMS_SIGNATURE_NO_SIGNER to create no sigInfo (no
     * signatures).
     */
    if ((flags & HX509_CMS_SIGNATURE_NO_SIGNER) == 0) {
	ret = hx509_certs_iter_f(context, certs, sig_process, &sigctx);
	if (ret)
	    goto out;
    }

    if (sigctx.sd.signerInfos.len) {

	/*
	 * For each signerInfo, collect all different digest types.
	 */
	for (i = 0; i < sigctx.sd.signerInfos.len; i++) {
	    AlgorithmIdentifier *di =
		&sigctx.sd.signerInfos.val[i].digestAlgorithm;

	    for (j = 0; j < sigctx.sd.digestAlgorithms.len; j++)
		if (cmp_AlgorithmIdentifier(di, &sigctx.sd.digestAlgorithms.val[j]) == 0)
		    break;
	    if (j == sigctx.sd.digestAlgorithms.len) {
		ret = add_DigestAlgorithmIdentifiers(&sigctx.sd.digestAlgorithms, di);
		if (ret) {
		    hx509_clear_error_string(context);
		    goto out;
		}
	    }
	}
    }

    /*
     * Add certs we think are needed, build as part of sig_process
     */
    if (sigctx.certs) {
	ALLOC(sigctx.sd.certificates, 1);
	if (sigctx.sd.certificates == NULL) {
	    hx509_clear_error_string(context);
	    ret = ENOMEM;
	    goto out;
	}

	ret = hx509_certs_iter_f(context, sigctx.certs, cert_process, &sigctx);
	if (ret)
	    goto out;
    }

    ASN1_MALLOC_ENCODE(SignedData,
		       signed_data->data, signed_data->length,
		       &sigctx.sd, &size, ret);
    if (ret) {
	hx509_clear_error_string(context);
	goto out;
    }
    if (signed_data->length != size)
	_hx509_abort("internal ASN.1 encoder error");

out:
    hx509_certs_free(&sigctx.certs);
    free_SignedData(&sigctx.sd);

    return ret;
}
Beispiel #15
0
int
hx509_ocsp_request(hx509_context context,
		   hx509_certs reqcerts,
		   hx509_certs pool,
		   hx509_cert signer,
		   const AlgorithmIdentifier *digest,
		   heim_octet_string *request,
		   heim_octet_string *nonce)
{
    OCSPRequest req;
    size_t size;
    int ret;
    struct ocsp_add_ctx ctx;
    Extensions *es;

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

    if (digest == NULL)
	digest = _hx509_crypto_default_digest_alg;

    ctx.req = &req.tbsRequest;
    ctx.certs = pool;
    ctx.digest = digest;
    ctx.parent = NULL;

    ret = hx509_certs_iter_f(context, reqcerts, add_to_req, &ctx);
    hx509_cert_free(ctx.parent);
    if (ret)
	goto out;

    if (nonce) {
	req.tbsRequest.requestExtensions =
	    calloc(1, sizeof(*req.tbsRequest.requestExtensions));
	if (req.tbsRequest.requestExtensions == NULL) {
	    ret = ENOMEM;
	    goto out;
	}

	es = req.tbsRequest.requestExtensions;

	es->val = calloc(es->len, sizeof(es->val[0]));
	if (es->val == NULL) {
	    ret = ENOMEM;
	    goto out;
	}
	es->len = 1;
	ret = der_copy_oid(&asn1_oid_id_pkix_ocsp_nonce, &es->val[0].extnID);
	if (ret) {
	    free_OCSPRequest(&req);
	    return ret;
	}

	es->val[0].extnValue.data = malloc(10);
	if (es->val[0].extnValue.data == NULL) {
	    ret = ENOMEM;
	    goto out;
	}
	es->val[0].extnValue.length = 10;

	ret = RAND_bytes(es->val[0].extnValue.data,
			 es->val[0].extnValue.length);
	if (ret != 1) {
	    ret = HX509_CRYPTO_INTERNAL_ERROR;
	    goto out;
	}
	ret = der_copy_octet_string(nonce, &es->val[0].extnValue);
	if (ret) {
	    ret = ENOMEM;
	    goto out;
	}
    }

    ASN1_MALLOC_ENCODE(OCSPRequest, request->data, request->length,
		       &req, &size, ret);
    free_OCSPRequest(&req);
    if (ret)
	goto out;
    if (size != request->length)
	_hx509_abort("internal ASN.1 encoder error");

    return 0;

out:
    free_OCSPRequest(&req);
    return ret;
}
Beispiel #16
0
static int
p12_store(hx509_context context,
	  hx509_certs certs, void *data, int flags, hx509_lock lock)
{
    struct ks_pkcs12 *p12 = data;
    PKCS12_PFX pfx;
    PKCS12_AuthenticatedSafe as;
    PKCS12_OctetString asdata;
    size_t size;
    int ret;

    memset(&as, 0, sizeof(as));
    memset(&pfx, 0, sizeof(pfx));

    ret = hx509_certs_iter_f(context, p12->certs, store_func, &as);
    if (ret)
	goto out;

    ASN1_MALLOC_ENCODE(PKCS12_AuthenticatedSafe, asdata.data, asdata.length,
		       &as, &size, ret);
    free_PKCS12_AuthenticatedSafe(&as);
    if (ret)
	return ret;

    ret = der_parse_hex_heim_integer("03", &pfx.version);
    if (ret) {
	free(asdata.data);
	goto out;
    }

    pfx.authSafe.content = calloc(1, sizeof(*pfx.authSafe.content));

    ASN1_MALLOC_ENCODE(PKCS12_OctetString,
		       pfx.authSafe.content->data,
		       pfx.authSafe.content->length,
		       &asdata, &size, ret);
    free(asdata.data);
    if (ret)
	goto out;

    ret = der_copy_oid(&asn1_oid_id_pkcs7_data, &pfx.authSafe.contentType);
    if (ret)
	goto out;

    ASN1_MALLOC_ENCODE(PKCS12_PFX, asdata.data, asdata.length,
		       &pfx, &size, ret);
    if (ret)
	goto out;

#if 0
    const struct _hx509_password *pw;

    pw = _hx509_lock_get_passwords(lock);
    if (pw != NULL) {
	pfx.macData = calloc(1, sizeof(*pfx.macData));
	if (pfx.macData == NULL) {
	    ret = ENOMEM;
	    hx509_set_error_string(context, 0, ret, "malloc out of memory");
	    return ret;
	}
	if (pfx.macData == NULL) {
	    free(asdata.data);
	    goto out;
	}
    }
    ret = calculate_hash(&aspath, pw, pfx.macData);
#endif

    rk_dumpdata(p12->fn, asdata.data, asdata.length);
    free(asdata.data);

out:
    free_PKCS12_AuthenticatedSafe(&as);
    free_PKCS12_PFX(&pfx);

    return ret;
}
Beispiel #17
0
static int
store_func(hx509_context context, void *ctx, hx509_cert c)
{
    PKCS12_AuthenticatedSafe *as = ctx;
    PKCS12_OctetString os;
    PKCS12_CertBag cb;
    size_t size;
    int ret;

    memset(&os, 0, sizeof(os));
    memset(&cb, 0, sizeof(cb));

    os.data = NULL;
    os.length = 0;

    ret = hx509_cert_binary(context, c, &os);
    if (ret)
	return ret;

    ASN1_MALLOC_ENCODE(PKCS12_OctetString,
		       cb.certValue.data,cb.certValue.length,
		       &os, &size, ret);
    free(os.data);
    if (ret)
	goto out;
    ret = der_copy_oid(&asn1_oid_id_pkcs_9_at_certTypes_x509, &cb.certType);
    if (ret) {
	free_PKCS12_CertBag(&cb);
	goto out;
    }
    ASN1_MALLOC_ENCODE(PKCS12_CertBag, os.data, os.length,
		       &cb, &size, ret);
    free_PKCS12_CertBag(&cb);
    if (ret)
	goto out;

    ret = addBag(context, as, &asn1_oid_id_pkcs12_certBag, os.data, os.length);

    if (_hx509_cert_private_key_exportable(c)) {
	hx509_private_key key = _hx509_cert_private_key(c);
	PKCS8PrivateKeyInfo pki;

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

	ret = der_parse_hex_heim_integer("00", &pki.version);
	if (ret)
	    return ret;
	ret = _hx509_private_key_oid(context, key,
				     &pki.privateKeyAlgorithm.algorithm);
	if (ret) {
	    free_PKCS8PrivateKeyInfo(&pki);
	    return ret;
	}
	ret = _hx509_private_key_export(context,
					_hx509_cert_private_key(c),
					HX509_KEY_FORMAT_DER,
					&pki.privateKey);
	if (ret) {
	    free_PKCS8PrivateKeyInfo(&pki);
	    return ret;
	}
	/* set attribute, asn1_oid_id_pkcs_9_at_localKeyId */

	ASN1_MALLOC_ENCODE(PKCS8PrivateKeyInfo, os.data, os.length,
			   &pki, &size, ret);
	free_PKCS8PrivateKeyInfo(&pki);
	if (ret)
	    return ret;

	ret = addBag(context, as, &asn1_oid_id_pkcs12_keyBag, os.data, os.length);
	if (ret)
	    return ret;
    }

out:
    return ret;
}
Beispiel #18
0
static int
ca_sign(hx509_context context,
	hx509_ca_tbs tbs,
	hx509_private_key signer,
	const AuthorityKeyIdentifier *ai,
	const Name *issuername,
	hx509_cert *certificate)
{
    heim_octet_string data;
    Certificate c;
    TBSCertificate *tbsc;
    size_t size;
    int ret;
    const AlgorithmIdentifier *sigalg;
    time_t notBefore;
    time_t notAfter;
    unsigned key_usage;

    sigalg = _hx509_crypto_default_sig_alg;

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

    /*
     * Default values are: Valid since 24h ago, valid one year into
     * the future, KeyUsage digitalSignature and keyEncipherment set,
     * and keyCertSign for CA certificates.
     */
    notBefore = tbs->notBefore;
    if (notBefore == 0)
	notBefore = time(NULL) - 3600 * 24;
    notAfter = tbs->notAfter;
    if (notAfter == 0)
	notAfter = time(NULL) + 3600 * 24 * 365;

    key_usage = tbs->key_usage;
    if (key_usage == 0) {
	KeyUsage ku;
	memset(&ku, 0, sizeof(ku));
	ku.digitalSignature = 1;
	ku.keyEncipherment = 1;
	key_usage = KeyUsage2int(ku);
    }

    if (tbs->flags.ca) {
	KeyUsage ku;
	memset(&ku, 0, sizeof(ku));
	ku.keyCertSign = 1;
	ku.cRLSign = 1;
	key_usage |= KeyUsage2int(ku);
    }

    /*
     *
     */

    tbsc = &c.tbsCertificate;

    if (tbs->flags.key == 0) {
	ret = EINVAL;
	hx509_set_error_string(context, 0, ret, "No public key set");
	return ret;
    }
    /*
     * Don't put restrictions on proxy certificate's subject name, it
     * will be generated below.
     */
    if (!tbs->flags.proxy) {
	if (tbs->subject == NULL) {
	    hx509_set_error_string(context, 0, EINVAL, "No subject name set");
	    return EINVAL;
	}
	if (hx509_name_is_null_p(tbs->subject) && tbs->san.len == 0) {
	    hx509_set_error_string(context, 0, EINVAL,
				   "NULL subject and no SubjectAltNames");
	    return EINVAL;
	}
    }
    if (tbs->flags.ca && tbs->flags.proxy) {
	hx509_set_error_string(context, 0, EINVAL, "Can't be proxy and CA "
			       "at the same time");
	return EINVAL;
    }
    if (tbs->flags.proxy) {
	if (tbs->san.len > 0) {
	    hx509_set_error_string(context, 0, EINVAL,
				   "Proxy certificate is not allowed "
				   "to have SubjectAltNames");
	    return EINVAL;
	}
    }

    /* version         [0]  Version OPTIONAL, -- EXPLICIT nnn DEFAULT 1, */
    tbsc->version = calloc(1, sizeof(*tbsc->version));
    if (tbsc->version == NULL) {
	ret = ENOMEM;
	hx509_set_error_string(context, 0, ret, "Out of memory");
	goto out;
    }
    *tbsc->version = rfc3280_version_3;
    /* serialNumber         CertificateSerialNumber, */
    if (tbs->flags.serial) {
	ret = der_copy_heim_integer(&tbs->serial, &tbsc->serialNumber);
	if (ret) {
	    hx509_set_error_string(context, 0, ret, "Out of memory");
	    goto out;
	}
    } else {
	tbsc->serialNumber.length = 20;
	tbsc->serialNumber.data = malloc(tbsc->serialNumber.length);
	if (tbsc->serialNumber.data == NULL){
	    ret = ENOMEM;
	    hx509_set_error_string(context, 0, ret, "Out of memory");
	    goto out;
	}
	/* XXX diffrent */
	RAND_bytes(tbsc->serialNumber.data, tbsc->serialNumber.length);
	((unsigned char *)tbsc->serialNumber.data)[0] &= 0x7f;
    }
    /* signature            AlgorithmIdentifier, */
    ret = copy_AlgorithmIdentifier(sigalg, &tbsc->signature);
    if (ret) {
	hx509_set_error_string(context, 0, ret, "Failed to copy sigature alg");
	goto out;
    }
    /* issuer               Name, */
    if (issuername)
	ret = copy_Name(issuername, &tbsc->issuer);
    else
	ret = hx509_name_to_Name(tbs->subject, &tbsc->issuer);
    if (ret) {
	hx509_set_error_string(context, 0, ret, "Failed to copy issuer name");
	goto out;
    }
    /* validity             Validity, */
    tbsc->validity.notBefore.element = choice_Time_generalTime;
    tbsc->validity.notBefore.u.generalTime = notBefore;
    tbsc->validity.notAfter.element = choice_Time_generalTime;
    tbsc->validity.notAfter.u.generalTime = notAfter;
    /* subject              Name, */
    if (tbs->flags.proxy) {
	ret = build_proxy_prefix(context, &tbsc->issuer, &tbsc->subject);
	if (ret)
	    goto out;
    } else {
	ret = hx509_name_to_Name(tbs->subject, &tbsc->subject);
	if (ret) {
	    hx509_set_error_string(context, 0, ret,
				   "Failed to copy subject name");
	    goto out;
	}
    }
    /* subjectPublicKeyInfo SubjectPublicKeyInfo, */
    ret = copy_SubjectPublicKeyInfo(&tbs->spki, &tbsc->subjectPublicKeyInfo);
    if (ret) {
	hx509_set_error_string(context, 0, ret, "Failed to copy spki");
	goto out;
    }
    /* issuerUniqueID  [1]  IMPLICIT BIT STRING OPTIONAL */
    if (tbs->issuerUniqueID.length) {
	tbsc->issuerUniqueID = calloc(1, sizeof(*tbsc->issuerUniqueID));
	if (tbsc->issuerUniqueID == NULL) {
	    ret = ENOMEM;
	    hx509_set_error_string(context, 0, ret, "Out of memory");
	    goto out;
	}
	ret = der_copy_bit_string(&tbs->issuerUniqueID, tbsc->issuerUniqueID);
	if (ret) {
	    hx509_set_error_string(context, 0, ret, "Out of memory");
	    goto out;
	}
    }
    /* subjectUniqueID [2]  IMPLICIT BIT STRING OPTIONAL */
    if (tbs->subjectUniqueID.length) {
	tbsc->subjectUniqueID = calloc(1, sizeof(*tbsc->subjectUniqueID));
	if (tbsc->subjectUniqueID == NULL) {
	    ret = ENOMEM;
	    hx509_set_error_string(context, 0, ret, "Out of memory");
	    goto out;
	}

	ret = der_copy_bit_string(&tbs->subjectUniqueID, tbsc->subjectUniqueID);
	if (ret) {
	    hx509_set_error_string(context, 0, ret, "Out of memory");
	    goto out;
	}
    }

    /* extensions      [3]  EXPLICIT Extensions OPTIONAL */
    tbsc->extensions = calloc(1, sizeof(*tbsc->extensions));
    if (tbsc->extensions == NULL) {
	ret = ENOMEM;
	hx509_set_error_string(context, 0, ret, "Out of memory");
	goto out;
    }

    /* Add the text BMP string Domaincontroller to the cert */
    if (tbs->flags.domaincontroller) {
	data.data = rk_UNCONST("\x1e\x20\x00\x44\x00\x6f\x00\x6d"
			       "\x00\x61\x00\x69\x00\x6e\x00\x43"
			       "\x00\x6f\x00\x6e\x00\x74\x00\x72"
			       "\x00\x6f\x00\x6c\x00\x6c\x00\x65"
			       "\x00\x72");
	data.length = 34;

	ret = add_extension(context, tbsc, 0,
			    &asn1_oid_id_ms_cert_enroll_domaincontroller,
			    &data);
	if (ret)
	    goto out;
    }

    /* add KeyUsage */
    {
	KeyUsage ku;

	ku = int2KeyUsage(key_usage);
	ASN1_MALLOC_ENCODE(KeyUsage, data.data, data.length, &ku, &size, ret);
	if (ret) {
	    hx509_set_error_string(context, 0, ret, "Out of memory");
	    goto out;
	}
	if (size != data.length)
	    _hx509_abort("internal ASN.1 encoder error");
	ret = add_extension(context, tbsc, 1,
			    &asn1_oid_id_x509_ce_keyUsage, &data);
	free(data.data);
	if (ret)
	    goto out;
    }

    /* add ExtendedKeyUsage */
    if (tbs->eku.len > 0) {
	ASN1_MALLOC_ENCODE(ExtKeyUsage, data.data, data.length,
			   &tbs->eku, &size, ret);
	if (ret) {
	    hx509_set_error_string(context, 0, ret, "Out of memory");
	    goto out;
	}
	if (size != data.length)
	    _hx509_abort("internal ASN.1 encoder error");
	ret = add_extension(context, tbsc, 0,
			    &asn1_oid_id_x509_ce_extKeyUsage, &data);
	free(data.data);
	if (ret)
	    goto out;
    }

    /* add Subject Alternative Name */
    if (tbs->san.len > 0) {
	ASN1_MALLOC_ENCODE(GeneralNames, data.data, data.length,
			   &tbs->san, &size, ret);
	if (ret) {
	    hx509_set_error_string(context, 0, ret, "Out of memory");
	    goto out;
	}
	if (size != data.length)
	    _hx509_abort("internal ASN.1 encoder error");
	ret = add_extension(context, tbsc, 0,
			    &asn1_oid_id_x509_ce_subjectAltName,
			    &data);
	free(data.data);
	if (ret)
	    goto out;
    }

    /* Add Authority Key Identifier */
    if (ai) {
	ASN1_MALLOC_ENCODE(AuthorityKeyIdentifier, data.data, data.length,
			   ai, &size, ret);
	if (ret) {
	    hx509_set_error_string(context, 0, ret, "Out of memory");
	    goto out;
	}
	if (size != data.length)
	    _hx509_abort("internal ASN.1 encoder error");
	ret = add_extension(context, tbsc, 0,
			    &asn1_oid_id_x509_ce_authorityKeyIdentifier,
			    &data);
	free(data.data);
	if (ret)
	    goto out;
    }

    /* Add Subject Key Identifier */
    {
	SubjectKeyIdentifier si;
	unsigned char hash[SHA_DIGEST_LENGTH];

	{
	    EVP_MD_CTX *ctx;

	    ctx = EVP_MD_CTX_create();
	    EVP_DigestInit_ex(ctx, EVP_sha1(), NULL);
	    EVP_DigestUpdate(ctx, tbs->spki.subjectPublicKey.data,
			     tbs->spki.subjectPublicKey.length / 8);
	    EVP_DigestFinal_ex(ctx, hash, NULL);
	    EVP_MD_CTX_destroy(ctx);
	}

	si.data = hash;
	si.length = sizeof(hash);

	ASN1_MALLOC_ENCODE(SubjectKeyIdentifier, data.data, data.length,
			   &si, &size, ret);
	if (ret) {
	    hx509_set_error_string(context, 0, ret, "Out of memory");
	    goto out;
	}
	if (size != data.length)
	    _hx509_abort("internal ASN.1 encoder error");
	ret = add_extension(context, tbsc, 0,
			    &asn1_oid_id_x509_ce_subjectKeyIdentifier,
			    &data);
	free(data.data);
	if (ret)
	    goto out;
    }

    /* Add BasicConstraints */
    {
	BasicConstraints bc;
	int aCA = 1;
	unsigned int path;

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

	if (tbs->flags.ca) {
	    bc.cA = &aCA;
	    if (tbs->pathLenConstraint >= 0) {
		path = tbs->pathLenConstraint;
		bc.pathLenConstraint = &path;
	    }
	}

	ASN1_MALLOC_ENCODE(BasicConstraints, data.data, data.length,
			   &bc, &size, ret);
	if (ret) {
	    hx509_set_error_string(context, 0, ret, "Out of memory");
	    goto out;
	}
	if (size != data.length)
	    _hx509_abort("internal ASN.1 encoder error");
	/* Critical if this is a CA */
	ret = add_extension(context, tbsc, tbs->flags.ca,
			    &asn1_oid_id_x509_ce_basicConstraints,
			    &data);
	free(data.data);
	if (ret)
	    goto out;
    }

    /* add Proxy */
    if (tbs->flags.proxy) {
	ProxyCertInfo info;

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

	if (tbs->pathLenConstraint >= 0) {
	    info.pCPathLenConstraint =
		malloc(sizeof(*info.pCPathLenConstraint));
	    if (info.pCPathLenConstraint == NULL) {
		ret = ENOMEM;
		hx509_set_error_string(context, 0, ret, "Out of memory");
		goto out;
	    }
	    *info.pCPathLenConstraint = tbs->pathLenConstraint;
	}

	ret = der_copy_oid(&asn1_oid_id_pkix_ppl_inheritAll,
			   &info.proxyPolicy.policyLanguage);
	if (ret) {
	    free_ProxyCertInfo(&info);
	    hx509_set_error_string(context, 0, ret, "Out of memory");
	    goto out;
	}

	ASN1_MALLOC_ENCODE(ProxyCertInfo, data.data, data.length,
			   &info, &size, ret);
	free_ProxyCertInfo(&info);
	if (ret) {
	    hx509_set_error_string(context, 0, ret, "Out of memory");
	    goto out;
	}
	if (size != data.length)
	    _hx509_abort("internal ASN.1 encoder error");
	ret = add_extension(context, tbsc, 0,
			    &asn1_oid_id_pkix_pe_proxyCertInfo,
			    &data);
	free(data.data);
	if (ret)
	    goto out;
    }

    if (tbs->crldp.len) {

	ASN1_MALLOC_ENCODE(CRLDistributionPoints, data.data, data.length,
			   &tbs->crldp, &size, ret);
	if (ret) {
	    hx509_set_error_string(context, 0, ret, "Out of memory");
	    goto out;
	}
	if (size != data.length)
	    _hx509_abort("internal ASN.1 encoder error");
	ret = add_extension(context, tbsc, FALSE,
			    &asn1_oid_id_x509_ce_cRLDistributionPoints,
			    &data);
	free(data.data);
	if (ret)
	    goto out;
    }

    ASN1_MALLOC_ENCODE(TBSCertificate, data.data, data.length,tbsc, &size, ret);
    if (ret) {
	hx509_set_error_string(context, 0, ret, "malloc out of memory");
	goto out;
    }
    if (data.length != size)
	_hx509_abort("internal ASN.1 encoder error");

    ret = _hx509_create_signature_bitstring(context,
					    signer,
					    sigalg,
					    &data,
					    &c.signatureAlgorithm,
					    &c.signatureValue);
    free(data.data);
    if (ret)
	goto out;

    ret = hx509_cert_init(context, &c, certificate);
    if (ret)
	goto out;

    free_Certificate(&c);

    return 0;

out:
    free_Certificate(&c);
    return ret;
}
Beispiel #19
0
int
hx509_cms_create_signed(hx509_context context,
			int flags,
			const heim_oid *eContentType,
			const void *data, size_t length,
			const AlgorithmIdentifier *digest_alg,
			hx509_certs certs,
			hx509_peer_info peer,
			hx509_certs anchors,
			hx509_certs pool,
			heim_octet_string *signed_data)
{
    unsigned int i;
    hx509_name name;
    int ret;
    size_t size;
    struct sigctx sigctx;

    memset(&sigctx, 0, sizeof(sigctx));
    memset(&name, 0, sizeof(name));

    if (eContentType == NULL)
	eContentType = &asn1_oid_id_pkcs7_data;

    sigctx.digest_alg = digest_alg;
    sigctx.content.data = rk_UNCONST(data);
    sigctx.content.length = length;
    sigctx.eContentType = eContentType;
    sigctx.peer = peer;
    /**
     * Use HX509_CMS_SIGNATURE_ID_NAME to preferred use of issuer name
     * and serial number if possible. Otherwise subject key identifier
     * will preferred.
     */
    if (flags & HX509_CMS_SIGNATURE_ID_NAME)
	sigctx.cmsidflag = CMS_ID_NAME;
    else
	sigctx.cmsidflag = CMS_ID_SKI;

    ret = hx509_certs_init(context, "MEMORY:certs", 0, NULL, &sigctx.certs);
    if (ret)
	return ret;

    sigctx.anchors = anchors;
    sigctx.pool = pool;

    sigctx.sd.version = CMSVersion_v3;

    der_copy_oid(eContentType, &sigctx.sd.encapContentInfo.eContentType);

    /**
     * Use HX509_CMS_SIGNATURE_DETACHED to create detached signatures.
     */
    if ((flags & HX509_CMS_SIGNATURE_DETACHED) == 0) {
	ALLOC(sigctx.sd.encapContentInfo.eContent, 1);
	if (sigctx.sd.encapContentInfo.eContent == NULL) {
	    hx509_clear_error_string(context);
	    ret = ENOMEM;
	    goto out;
	}
	
	sigctx.sd.encapContentInfo.eContent->data = malloc(length);
	if (sigctx.sd.encapContentInfo.eContent->data == NULL) {
	    hx509_clear_error_string(context);
	    ret = ENOMEM;
	    goto out;
	}
	memcpy(sigctx.sd.encapContentInfo.eContent->data, data, length);
	sigctx.sd.encapContentInfo.eContent->length = length;
    }

    /**
     * Use HX509_CMS_SIGNATURE_NO_SIGNER to create no sigInfo (no
     * signatures).
     */
    if ((flags & HX509_CMS_SIGNATURE_NO_SIGNER) == 0) {
	ret = hx509_certs_iter(context, certs, sig_process, &sigctx);
	if (ret)
	    goto out;
    }

    if (sigctx.sd.signerInfos.len) {
	ALLOC_SEQ(&sigctx.sd.digestAlgorithms, sigctx.sd.signerInfos.len);
	if (sigctx.sd.digestAlgorithms.val == NULL) {
	    ret = ENOMEM;
	    hx509_clear_error_string(context);
	    goto out;
	}
	
	/* XXX remove dups */
	for (i = 0; i < sigctx.sd.signerInfos.len; i++) {
	    AlgorithmIdentifier *di =
		&sigctx.sd.signerInfos.val[i].digestAlgorithm;
	    ret = copy_AlgorithmIdentifier(di,
					   &sigctx.sd.digestAlgorithms.val[i]);
	    if (ret) {
		hx509_clear_error_string(context);
		goto out;
	    }
	}
    }

    if (sigctx.certs) {
	ALLOC(sigctx.sd.certificates, 1);
	if (sigctx.sd.certificates == NULL) {
	    hx509_clear_error_string(context);
	    ret = ENOMEM;
	    goto out;
	}

	ret = hx509_certs_iter(context, sigctx.certs, cert_process, &sigctx);
	if (ret)
	    goto out;
    }

    ASN1_MALLOC_ENCODE(SignedData,
		       signed_data->data, signed_data->length,
		       &sigctx.sd, &size, ret);
    if (ret) {
	hx509_clear_error_string(context);
	goto out;
    }
    if (signed_data->length != size)
	_hx509_abort("internal ASN.1 encoder error");

out:
    hx509_certs_free(&sigctx.certs);
    free_SignedData(&sigctx.sd);

    return ret;
}