Exemplo n.º 1
0
int
hx509_crl_add_revoked_certs(hx509_context context,
			    hx509_crl crl,
			    hx509_certs certs)
{
    return hx509_certs_merge(context, crl->revoked, certs);
}
Exemplo n.º 2
0
int
_hx509_collector_collect_certs(hx509_context context,
			       struct hx509_collector *c,
			       hx509_certs *ret_certs)
{
    hx509_certs certs;
    int ret, i;

    *ret_certs = NULL;

    ret = hx509_certs_init(context, "MEMORY:collector-store", 0, NULL, &certs);
    if (ret)
	return ret;

    ret = hx509_certs_merge(context, certs, c->certs);
    if (ret) {
	hx509_certs_free(&certs);
	return ret;
    }

    for (i = 0; i < c->val.len; i++) {
	ret = match_localkeyid(context, c->val.data[i], certs);
	if (ret == 0)
	    continue;
	ret = match_keys(context, c->val.data[i], certs);
	if (ret == 0)
	    continue;
    }

    *ret_certs = certs;

    return 0;
}
Exemplo n.º 3
0
int
hx509_certs_append(hx509_context context,
		   hx509_certs to,
		   hx509_lock lock,
		   const char *name)
{
    hx509_certs s;
    int ret;

    ret = hx509_certs_init(context, name, 0, lock, &s);
    if (ret)
	return ret;
    ret = hx509_certs_merge(context, to, s);
    hx509_certs_free(&s);
    return ret;
}
Exemplo n.º 4
0
Arquivo: ks_p11.c Projeto: hyc/heimdal
static int
p11_iter_start(hx509_context context,
	       hx509_certs certs, void *data, void **cursor)
{
    struct p11_module *p = data;
    struct p11_cursor *c;
    int ret;
    size_t i;

    c = malloc(sizeof(*c));
    if (c == NULL) {
	hx509_clear_error_string(context);
	return ENOMEM;
    }
    ret = hx509_certs_init(context, "MEMORY:pkcs11-iter", 0, NULL, &c->certs);
    if (ret) {
	free(c);
	return ret;
    }

    for (i = 0 ; i < p->num_slots; i++) {
	if (p->slot[i].certs == NULL)
	    continue;
	ret = hx509_certs_merge(context, c->certs, p->slot[i].certs);
	if (ret) {
	    hx509_certs_free(&c->certs);
	    free(c);
	    return ret;
	}
    }

    ret = hx509_certs_start_seq(context, c->certs, &c->cursor);
    if (ret) {
	hx509_certs_free(&c->certs);
	free(c);
	return 0;
    }
    *cursor = c;

    return 0;
}
Exemplo n.º 5
0
int
hx509_lock_add_certs(hx509_context context, hx509_lock lock, hx509_certs certs)
{
    return hx509_certs_merge(context, lock->certs, certs);
}
Exemplo n.º 6
0
krb5_error_code
_kdc_pk_rd_padata(krb5_context context,
		  krb5_kdc_configuration *config,
		  const KDC_REQ *req,
		  const PA_DATA *pa,
		  hdb_entry_ex *client,
		  pk_client_params **ret_params)
{
    pk_client_params *cp;
    krb5_error_code ret;
    heim_oid eContentType = { 0, NULL }, contentInfoOid = { 0, NULL };
    krb5_data eContent = { 0, NULL };
    krb5_data signed_content = { 0, NULL };
    const char *type = "unknown type";
    hx509_certs trust_anchors;
    int have_data = 0;
    const HDB_Ext_PKINIT_cert *pc;

    *ret_params = NULL;

    if (!config->enable_pkinit) {
	kdc_log(context, config, 0, "PK-INIT request but PK-INIT not enabled");
	krb5_clear_error_message(context);
	return 0;
    }

    cp = calloc(1, sizeof(*cp));
    if (cp == NULL) {
	krb5_clear_error_message(context);
	ret = ENOMEM;
	goto out;
    }

    ret = hx509_certs_init(context->hx509ctx,
			   "MEMORY:trust-anchors",
			   0, NULL, &trust_anchors);
    if (ret) {
	krb5_set_error_message(context, ret, "failed to create trust anchors");
	goto out;
    }

    ret = hx509_certs_merge(context->hx509ctx, trust_anchors,
			    kdc_identity->anchors);
    if (ret) {
	hx509_certs_free(&trust_anchors);
	krb5_set_error_message(context, ret, "failed to create verify context");
	goto out;
    }

    /* Add any registered certificates for this client as trust anchors */
    ret = hdb_entry_get_pkinit_cert(&client->entry, &pc);
    if (ret == 0 && pc != NULL) {
	hx509_cert cert;
	unsigned int i;

	for (i = 0; i < pc->len; i++) {
	    cert = hx509_cert_init_data(context->hx509ctx,
					pc->val[i].cert.data,
					pc->val[i].cert.length,
					NULL);
	    if (cert == NULL)
		continue;
	    hx509_certs_add(context->hx509ctx, trust_anchors, cert);
	    hx509_cert_free(cert);
	}
    }

    ret = hx509_verify_init_ctx(context->hx509ctx, &cp->verify_ctx);
    if (ret) {
	hx509_certs_free(&trust_anchors);
	krb5_set_error_message(context, ret, "failed to create verify context");
	goto out;
    }

    hx509_verify_set_time(cp->verify_ctx, kdc_time);
    hx509_verify_attach_anchors(cp->verify_ctx, trust_anchors);
    hx509_certs_free(&trust_anchors);

    if (config->pkinit_allow_proxy_certs)
	hx509_verify_set_proxy_certificate(cp->verify_ctx, 1);

    if (pa->padata_type == KRB5_PADATA_PK_AS_REQ_WIN) {
	PA_PK_AS_REQ_Win2k r;

	type = "PK-INIT-Win2k";

	if (_kdc_is_anon_request(&req->req_body)) {
	    ret = KRB5_KDC_ERR_PUBLIC_KEY_ENCRYPTION_NOT_SUPPORTED;
	    krb5_set_error_message(context, ret,
				   "Anon not supported in RSA mode");
	    goto out;
	}

	ret = decode_PA_PK_AS_REQ_Win2k(pa->padata_value.data,
					pa->padata_value.length,
					&r,
					NULL);
	if (ret) {
	    krb5_set_error_message(context, ret, "Can't decode "
				   "PK-AS-REQ-Win2k: %d", ret);
	    goto out;
	}

	ret = hx509_cms_unwrap_ContentInfo(&r.signed_auth_pack,
					   &contentInfoOid,
					   &signed_content,
					   &have_data);
	free_PA_PK_AS_REQ_Win2k(&r);
	if (ret) {
	    krb5_set_error_message(context, ret,
				   "Can't unwrap ContentInfo(win): %d", ret);
	    goto out;
	}

    } else if (pa->padata_type == KRB5_PADATA_PK_AS_REQ) {
	PA_PK_AS_REQ r;

	type = "PK-INIT-IETF";

	ret = decode_PA_PK_AS_REQ(pa->padata_value.data,
				  pa->padata_value.length,
				  &r,
				  NULL);
	if (ret) {
	    krb5_set_error_message(context, ret,
				   "Can't decode PK-AS-REQ: %d", ret);
	    goto out;
	}

	/* XXX look at r.kdcPkId */
	if (r.trustedCertifiers) {
	    ExternalPrincipalIdentifiers *edi = r.trustedCertifiers;
	    unsigned int i, maxedi;

	    ret = hx509_certs_init(context->hx509ctx,
				   "MEMORY:client-anchors",
				   0, NULL,
				   &cp->client_anchors);
	    if (ret) {
		krb5_set_error_message(context, ret,
				       "Can't allocate client anchors: %d",
				       ret);
		goto out;

	    }
	    /*
	     * If the client sent more then 10 EDI, don't bother
	     * looking more then 10 of performance reasons.
	     */
	    maxedi = edi->len;
	    if (maxedi > 10)
		maxedi = 10;
	    for (i = 0; i < maxedi; i++) {
		IssuerAndSerialNumber iasn;
		hx509_query *q;
		hx509_cert cert;
		size_t size;

		if (edi->val[i].issuerAndSerialNumber == NULL)
		    continue;

		ret = hx509_query_alloc(context->hx509ctx, &q);
		if (ret) {
		    krb5_set_error_message(context, ret,
					  "Failed to allocate hx509_query");
		    goto out;
		}

		ret = decode_IssuerAndSerialNumber(edi->val[i].issuerAndSerialNumber->data,
						   edi->val[i].issuerAndSerialNumber->length,
						   &iasn,
						   &size);
		if (ret) {
		    hx509_query_free(context->hx509ctx, q);
		    continue;
		}
		ret = hx509_query_match_issuer_serial(q, &iasn.issuer, &iasn.serialNumber);
		free_IssuerAndSerialNumber(&iasn);
		if (ret) {
		    hx509_query_free(context->hx509ctx, q);
		    continue;
		}

		ret = hx509_certs_find(context->hx509ctx,
				       kdc_identity->certs,
				       q,
				       &cert);
		hx509_query_free(context->hx509ctx, q);
		if (ret)
		    continue;
		hx509_certs_add(context->hx509ctx,
				cp->client_anchors, cert);
		hx509_cert_free(cert);
	    }
	}

	ret = hx509_cms_unwrap_ContentInfo(&r.signedAuthPack,
					   &contentInfoOid,
					   &signed_content,
					   &have_data);
	free_PA_PK_AS_REQ(&r);
	if (ret) {
	    krb5_set_error_message(context, ret,
				   "Can't unwrap ContentInfo: %d", ret);
	    goto out;
	}

    } else {
	krb5_clear_error_message(context);
	ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
	goto out;
    }

    ret = der_heim_oid_cmp(&contentInfoOid, &asn1_oid_id_pkcs7_signedData);
    if (ret != 0) {
	ret = KRB5KRB_ERR_GENERIC;
	krb5_set_error_message(context, ret,
			       "PK-AS-REQ-Win2k invalid content type oid");
	goto out;
    }

    if (!have_data) {
	ret = KRB5KRB_ERR_GENERIC;
	krb5_set_error_message(context, ret,
			      "PK-AS-REQ-Win2k no signed auth pack");
	goto out;
    }

    {
	hx509_certs signer_certs;
	int flags = HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH; /* BTMM */

	if (_kdc_is_anon_request(&req->req_body))
	    flags |= HX509_CMS_VS_ALLOW_ZERO_SIGNER;

	ret = hx509_cms_verify_signed(context->hx509ctx,
				      cp->verify_ctx,
				      flags,
				      signed_content.data,
				      signed_content.length,
				      NULL,
				      kdc_identity->certpool,
				      &eContentType,
				      &eContent,
				      &signer_certs);
	if (ret) {
	    char *s = hx509_get_error_string(context->hx509ctx, ret);
	    krb5_warnx(context, "PKINIT: failed to verify signature: %s: %d",
		       s, ret);
	    free(s);
	    goto out;
	}

	if (signer_certs) {
	    ret = hx509_get_one_cert(context->hx509ctx, signer_certs,
				     &cp->cert);
	    hx509_certs_free(&signer_certs);
	}
	if (ret)
	    goto out;
    }

    /* Signature is correct, now verify the signed message */
    if (der_heim_oid_cmp(&eContentType, &asn1_oid_id_pkcs7_data) != 0 &&
	der_heim_oid_cmp(&eContentType, &asn1_oid_id_pkauthdata) != 0)
    {
	ret = KRB5_BADMSGTYPE;
	krb5_set_error_message(context, ret, "got wrong oid for pkauthdata");
	goto out;
    }

    if (pa->padata_type == KRB5_PADATA_PK_AS_REQ_WIN) {
	AuthPack_Win2k ap;

	ret = decode_AuthPack_Win2k(eContent.data,
				    eContent.length,
				    &ap,
				    NULL);
	if (ret) {
	    krb5_set_error_message(context, ret,
				   "Can't decode AuthPack: %d", ret);
	    goto out;
	}

	ret = pk_check_pkauthenticator_win2k(context,
					     &ap.pkAuthenticator,
					     req);
	if (ret) {
	    free_AuthPack_Win2k(&ap);
	    goto out;
	}

	cp->type = PKINIT_WIN2K;
	cp->nonce = ap.pkAuthenticator.nonce;

	if (ap.clientPublicValue) {
	    ret = KRB5KRB_ERR_GENERIC;
	    krb5_set_error_message(context, ret,
				   "DH not supported for windows");
	    goto out;
	}
	free_AuthPack_Win2k(&ap);

    } else if (pa->padata_type == KRB5_PADATA_PK_AS_REQ) {
	AuthPack ap;

	ret = decode_AuthPack(eContent.data,
			      eContent.length,
			      &ap,
			      NULL);
	if (ret) {
	    krb5_set_error_message(context, ret,
				   "Can't decode AuthPack: %d", ret);
	    free_AuthPack(&ap);
	    goto out;
	}

	if (_kdc_is_anon_request(&req->req_body) &&
	    ap.clientPublicValue == NULL) {
	    free_AuthPack(&ap);
	    ret = KRB5_KDC_ERR_PUBLIC_KEY_ENCRYPTION_NOT_SUPPORTED;
	    krb5_set_error_message(context, ret,
				   "Anon not supported in RSA mode");
	    goto out;
	}

	ret = pk_check_pkauthenticator(context,
				       &ap.pkAuthenticator,
				       req);
	if (ret) {
	    free_AuthPack(&ap);
	    goto out;
	}

	cp->type = PKINIT_27;
	cp->nonce = ap.pkAuthenticator.nonce;

	if (ap.clientPublicValue) {
	    if (der_heim_oid_cmp(&ap.clientPublicValue->algorithm.algorithm, &asn1_oid_id_dhpublicnumber) == 0) {
		cp->keyex = USE_DH;
		ret = get_dh_param(context, config,
				   ap.clientPublicValue, cp);
	    } else if (der_heim_oid_cmp(&ap.clientPublicValue->algorithm.algorithm, &asn1_oid_id_ecPublicKey) == 0) {
		cp->keyex = USE_ECDH;
                ret = _kdc_get_ecdh_param(context, config,
                                          ap.clientPublicValue,
                                          &cp->u.ecdh.public_key);
	    } else {
		ret = KRB5_BADMSGTYPE;
		krb5_set_error_message(context, ret, "PKINIT unknown DH mechanism");
	    }
	    if (ret) {
		free_AuthPack(&ap);
		goto out;
	    }
	} else
	    cp->keyex = USE_RSA;

	ret = hx509_peer_info_alloc(context->hx509ctx,
					&cp->peer);
	if (ret) {
	    free_AuthPack(&ap);
	    goto out;
	}

	if (ap.supportedCMSTypes) {
	    ret = hx509_peer_info_set_cms_algs(context->hx509ctx,
					       cp->peer,
					       ap.supportedCMSTypes->val,
					       ap.supportedCMSTypes->len);
	    if (ret) {
		free_AuthPack(&ap);
		goto out;
	    }
	} else {
	    /* assume old client */
	    hx509_peer_info_add_cms_alg(context->hx509ctx, cp->peer,
					hx509_crypto_des_rsdi_ede3_cbc());
	    hx509_peer_info_add_cms_alg(context->hx509ctx, cp->peer,
					hx509_signature_rsa_with_sha1());
	    hx509_peer_info_add_cms_alg(context->hx509ctx, cp->peer,
					hx509_signature_sha1());
	}
	free_AuthPack(&ap);
    } else
	krb5_abortx(context, "internal pkinit error");

    kdc_log(context, config, 0, "PK-INIT request of type %s", type);

out:
    if (ret)
	krb5_warn(context, ret, "PKINIT");

    if (signed_content.data)
	free(signed_content.data);
    krb5_data_free(&eContent);
    der_free_oid(&eContentType);
    der_free_oid(&contentInfoOid);
    if (ret) {
        _kdc_pk_free_client_param(context, cp);
    } else
	*ret_params = cp;
    return ret;
}
Exemplo n.º 7
0
Arquivo: cms.c Projeto: InvLim/heimdal
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;
}