KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_c_set_checksum(krb5_context context, krb5_checksum *cksum, krb5_cksumtype type, const krb5_data *data) { cksum->cksumtype = type; return der_copy_octet_string(data, &cksum->checksum); }
int _hx509_collector_private_key_add(hx509_context context, struct hx509_collector *c, const AlgorithmIdentifier *alg, hx509_private_key private_key, const heim_octet_string *key_data, const heim_octet_string *localKeyId) { struct private_key *key; void *d; int ret; key = calloc(1, sizeof(*key)); if (key == NULL) return ENOMEM; d = realloc(c->val.data, (c->val.len + 1) * sizeof(c->val.data[0])); if (d == NULL) { free(key); hx509_set_error_string(context, 0, ENOMEM, "Out of memory"); return ENOMEM; } c->val.data = d; ret = copy_AlgorithmIdentifier(alg, &key->alg); if (ret) { hx509_set_error_string(context, 0, ret, "Failed to copy " "AlgorithmIdentifier"); goto out; } if (private_key) { key->private_key = private_key; } else { ret = hx509_parse_private_key(context, alg, key_data->data, key_data->length, HX509_KEY_FORMAT_DER, &key->private_key); if (ret) goto out; } if (localKeyId) { ret = der_copy_octet_string(localKeyId, &key->localKeyId); if (ret) { hx509_set_error_string(context, 0, ret, "Failed to copy localKeyId"); goto out; } } else memset(&key->localKeyId, 0, sizeof(key->localKeyId)); c->val.data[c->val.len] = key; c->val.len++; out: if (ret) free_private_key(key); return ret; }
static void set_salt_padata(METHOD_DATA *md, Salt *salt) { if (salt) { realloc_method_data(md); md->val[md->len - 1].padata_type = salt->type; der_copy_octet_string(&salt->salt, &md->val[md->len - 1].padata_value); } }
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_ntlm_init_get_opaque(krb5_context context, krb5_ntlm ntlm, krb5_data *opaque) { krb5_error_code ret; ret = der_copy_octet_string(&ntlm->initReply.opaque, opaque); if (ret) krb5_clear_error_message(context); return ret; }
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_digest_get_session_key(krb5_context context, krb5_digest digest, krb5_data *data) { krb5_error_code ret; krb5_data_zero(data); if (digest->response.session_key == NULL) return 0; ret = der_copy_octet_string(digest->response.session_key, data); if (ret) krb5_clear_error_message(context); return ret; }
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_copy_data(krb5_context context, const krb5_data *indata, krb5_data **outdata) { krb5_error_code ret; ALLOC(*outdata, 1); if(*outdata == NULL) return krb5_enomem(context); ret = der_copy_octet_string(indata, *outdata); if(ret) { krb5_clear_error_message (context); free(*outdata); *outdata = NULL; } return ret; }
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_copy_data(krb5_context context, const krb5_data *indata, krb5_data **outdata) { krb5_error_code ret; ALLOC(*outdata, 1); if(*outdata == NULL) { krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); return ENOMEM; } ret = der_copy_octet_string(indata, *outdata); if(ret) { krb5_clear_error_message (context); free(*outdata); *outdata = NULL; } return ret; }
static krb5_error_code find_KRB5SignedPath(krb5_context context, const AuthorizationData *ad, krb5_data *data) { AuthorizationData child; krb5_error_code ret; int pos; if (ad == NULL || ad->len == 0) return KRB5KDC_ERR_PADATA_TYPE_NOSUPP; pos = ad->len - 1; if (ad->val[pos].ad_type != KRB5_AUTHDATA_IF_RELEVANT) return KRB5KDC_ERR_PADATA_TYPE_NOSUPP; ret = decode_AuthorizationData(ad->val[pos].ad_data.data, ad->val[pos].ad_data.length, &child, NULL); if (ret) { krb5_set_error_string(context, "Failed to decode " "IF_RELEVANT with %d", ret); return ret; } if (child.len != 1) { free_AuthorizationData(&child); return KRB5KDC_ERR_PADATA_TYPE_NOSUPP; } if (child.val[0].ad_type != KRB5_AUTHDATA_SIGNTICKET) { free_AuthorizationData(&child); return KRB5KDC_ERR_PADATA_TYPE_NOSUPP; } if (data) ret = der_copy_octet_string(&child.val[0].ad_data, data); free_AuthorizationData(&child); return ret; }
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; }
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; }
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_c_get_checksum(krb5_context context, const krb5_checksum *cksum, krb5_cksumtype *type, krb5_data **data) { krb5_error_code ret; if (type) *type = cksum->cksumtype; if (data) { *data = malloc(sizeof(**data)); if (*data == NULL) return ENOMEM; ret = der_copy_octet_string(&cksum->checksum, *data); if (ret) { free(*data); *data = NULL; return ret; } } return 0; }
int hdb_entry_get_password(krb5_context context, HDB *db, const hdb_entry *entry, char **p) { HDB_extension *ext; char *str; int ret; ext = hdb_find_extension(entry, choice_HDB_extension_data_password); if (ext) { heim_utf8_string str; heim_octet_string pw; if (db->hdb_master_key_set && ext->data.u.password.mkvno) { hdb_master_key key; key = _hdb_find_master_key(ext->data.u.password.mkvno, db->hdb_master_key); if (key == NULL) { krb5_set_error_string(context, "master key %d missing", *ext->data.u.password.mkvno); return HDB_ERR_NO_MKEY; } ret = _hdb_mkey_decrypt(context, key, HDB_KU_MKEY, ext->data.u.password.password.data, ext->data.u.password.password.length, &pw); } else { ret = der_copy_octet_string(&ext->data.u.password.password, &pw); } if (ret) { krb5_clear_error_string(context); return ret; } str = pw.data; if (str[pw.length - 1] != '\0') { krb5_set_error_string(context, "password malformated"); return EINVAL; } *p = strdup(str); der_free_octet_string(&pw); if (*p == NULL) { krb5_set_error_string(context, "malloc: out of memory"); return ENOMEM; } return 0; } ret = krb5_unparse_name(context, entry->principal, &str); if (ret == 0) { krb5_set_error_string(context, "no password attributefor %s", str); free(str); } else krb5_clear_error_string(context); return ENOENT; }
static int get_AuthorityKeyIdentifier(hx509_context context, const Certificate *certificate, AuthorityKeyIdentifier *ai) { SubjectKeyIdentifier si; int ret; ret = _hx509_find_extension_subject_key_id(certificate, &si); if (ret == 0) { ai->keyIdentifier = calloc(1, sizeof(*ai->keyIdentifier)); if (ai->keyIdentifier == NULL) { free_SubjectKeyIdentifier(&si); ret = ENOMEM; hx509_set_error_string(context, 0, ret, "Out of memory"); goto out; } ret = der_copy_octet_string(&si, ai->keyIdentifier); free_SubjectKeyIdentifier(&si); if (ret) { hx509_set_error_string(context, 0, ret, "Out of memory"); goto out; } } else { GeneralNames gns; GeneralName gn; Name name; memset(&gn, 0, sizeof(gn)); memset(&gns, 0, sizeof(gns)); memset(&name, 0, sizeof(name)); ai->authorityCertIssuer = calloc(1, sizeof(*ai->authorityCertIssuer)); if (ai->authorityCertIssuer == NULL) { ret = ENOMEM; hx509_set_error_string(context, 0, ret, "Out of memory"); goto out; } ai->authorityCertSerialNumber = calloc(1, sizeof(*ai->authorityCertSerialNumber)); if (ai->authorityCertSerialNumber == NULL) { ret = ENOMEM; hx509_set_error_string(context, 0, ret, "Out of memory"); goto out; } /* * XXX unbreak when asn1 compiler handle IMPLICIT * * This is so horrible. */ ret = copy_Name(&certificate->tbsCertificate.subject, &name); if (ret) { hx509_set_error_string(context, 0, ret, "Out of memory"); goto out; } memset(&gn, 0, sizeof(gn)); gn.element = choice_GeneralName_directoryName; gn.u.directoryName.element = choice_GeneralName_directoryName_rdnSequence; gn.u.directoryName.u.rdnSequence = name.u.rdnSequence; ret = add_GeneralNames(&gns, &gn); if (ret) { hx509_set_error_string(context, 0, ret, "Out of memory"); goto out; } ai->authorityCertIssuer->val = gns.val; ai->authorityCertIssuer->len = gns.len; ret = der_copy_heim_integer(&certificate->tbsCertificate.serialNumber, ai->authorityCertSerialNumber); if (ai->authorityCertSerialNumber == NULL) { ret = ENOMEM; hx509_set_error_string(context, 0, ret, "Out of memory"); goto out; } } out: if (ret) free_AuthorityKeyIdentifier(ai); return ret; }
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; }
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; }
static int find_type_in_ad(krb5_context context, int type, krb5_data *data, krb5_boolean *found, krb5_boolean failp, krb5_keyblock *sessionkey, const AuthorizationData *ad, int level) { krb5_error_code ret = 0; size_t i; if (level > 9) { ret = ENOENT; /* XXX */ krb5_set_error_message(context, ret, N_("Authorization data nested deeper " "then %d levels, stop searching", ""), level); goto out; } /* * Only copy out the element the first time we get to it, we need * to run over the whole authorization data fields to check if * there are any container clases we need to care about. */ for (i = 0; i < ad->len; i++) { if (!*found && ad->val[i].ad_type == type) { ret = der_copy_octet_string(&ad->val[i].ad_data, data); if (ret) { krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto out; } *found = TRUE; continue; } switch (ad->val[i].ad_type) { case KRB5_AUTHDATA_IF_RELEVANT: { AuthorizationData child; ret = decode_AuthorizationData(ad->val[i].ad_data.data, ad->val[i].ad_data.length, &child, NULL); if (ret) { krb5_set_error_message(context, ret, N_("Failed to decode " "IF_RELEVANT with %d", ""), (int)ret); goto out; } ret = find_type_in_ad(context, type, data, found, FALSE, sessionkey, &child, level + 1); free_AuthorizationData(&child); if (ret) goto out; break; } #if 0 /* XXX test */ case KRB5_AUTHDATA_KDC_ISSUED: { AD_KDCIssued child; ret = decode_AD_KDCIssued(ad->val[i].ad_data.data, ad->val[i].ad_data.length, &child, NULL); if (ret) { krb5_set_error_message(context, ret, N_("Failed to decode " "AD_KDCIssued with %d", ""), ret); goto out; } if (failp) { krb5_boolean valid; krb5_data buf; size_t len; ASN1_MALLOC_ENCODE(AuthorizationData, buf.data, buf.length, &child.elements, &len, ret); if (ret) { free_AD_KDCIssued(&child); krb5_clear_error_message(context); goto out; } if(buf.length != len) krb5_abortx(context, "internal error in ASN.1 encoder"); ret = krb5_c_verify_checksum(context, sessionkey, 19, &buf, &child.ad_checksum, &valid); krb5_data_free(&buf); if (ret) { free_AD_KDCIssued(&child); goto out; } if (!valid) { krb5_clear_error_message(context); ret = ENOENT; free_AD_KDCIssued(&child); goto out; } } ret = find_type_in_ad(context, type, data, found, failp, sessionkey, &child.elements, level + 1); free_AD_KDCIssued(&child); if (ret) goto out; break; } #endif case KRB5_AUTHDATA_AND_OR: if (!failp) break; ret = ENOENT; /* XXX */ krb5_set_error_message(context, ret, N_("Authorization data contains " "AND-OR element that is unknown to the " "application", "")); goto out; default: if (!failp) break; ret = ENOENT; /* XXX */ krb5_set_error_message(context, ret, N_("Authorization data contains " "unknown type (%d) ", ""), ad->val[i].ad_type); goto out; } } out: if (ret) { if (*found) { krb5_data_free(data); *found = 0; } } return ret; }
int copy_heim_any(const heim_any *from, heim_any *to) { return der_copy_octet_string(from, to); }