[PATCH] Add support for MS Catalog files
Jeremy Allison
jra at samba.org
Tue Aug 7 19:21:07 UTC 2018
On Tue, Aug 07, 2018 at 11:40:39AM +0200, Andreas Schneider wrote:
>
> Updated patchset attached.
>
>
> Thanks for the review!
LGTM. Really nice, clean code - thanks !
Reviewed-by: Jeremy Allison <jra at samba.org>
However, it adds a dependency on the package libtasn1-bin
for the ans1Parser program.
You'll need to get root at sn-devel to install that,
or change the patch to gate the compilation of this binary on
availability of libtasn1-bin, as currently it won't
configure without it.
Jeremy.
> --
> Andreas Schneider asn at samba.org
> Samba Team www.samba.org
> GPG-ID: 8DFF53E18F2ABC8D8F3C92237EE0FC4DCC014E3D
> From 28c9596dcec930a8a3fb434bb0b31ad38e55cd5d Mon Sep 17 00:00:00 2001
> From: Andreas Schneider <asn at samba.org>
> Date: Tue, 20 Dec 2016 08:52:14 +0100
> Subject: [PATCH] lib: Add support to parse MS Catalog files
>
> Signed-off-by: Andreas Schneider <asn at samba.org>
> ---
> lib/mscat/dumpmscat.c | 188 ++++++
> lib/mscat/mscat.asn | 136 +++++
> lib/mscat/mscat.h | 105 ++++
> lib/mscat/mscat_ctl.c | 1194 +++++++++++++++++++++++++++++++++++++
> lib/mscat/mscat_pkcs7.c | 284 +++++++++
> lib/mscat/mscat_private.h | 27 +
> lib/mscat/wscript | 42 ++
> wscript | 1 +
> wscript_build | 1 +
> 9 files changed, 1978 insertions(+)
> create mode 100644 lib/mscat/dumpmscat.c
> create mode 100644 lib/mscat/mscat.asn
> create mode 100644 lib/mscat/mscat.h
> create mode 100644 lib/mscat/mscat_ctl.c
> create mode 100644 lib/mscat/mscat_pkcs7.c
> create mode 100644 lib/mscat/mscat_private.h
> create mode 100644 lib/mscat/wscript
>
> diff --git a/lib/mscat/dumpmscat.c b/lib/mscat/dumpmscat.c
> new file mode 100644
> index 00000000000..eac2184e7ad
> --- /dev/null
> +++ b/lib/mscat/dumpmscat.c
> @@ -0,0 +1,188 @@
> +/*
> + * Copyright (c) 2016 Andreas Schneider <asn at samba.org>
> + *
> + * This program is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, either version 3 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <errno.h>
> +#include <stdbool.h>
> +#include <stdarg.h>
> +#include <stdint.h>
> +#include <stdio.h>
> +
> +#include <talloc.h>
> +
> +#include <libtasn1.h>
> +#include <gnutls/pkcs7.h>
> +
> +#include "mscat.h"
> +
> +static const char *mac_to_string(enum mscat_mac_algorithm algo) {
> + switch(algo) {
> + case MSCAT_MAC_NULL:
> + return "NULL";
> + case MSCAT_MAC_MD5:
> + return "MD5";
> + case MSCAT_MAC_SHA1:
> + return "SHA1";
> + case MSCAT_MAC_SHA256:
> + return "SHA256";
> + case MSCAT_MAC_SHA512:
> + return "SHA512";
> + case MSCAT_MAC_UNKNOWN:
> + return "UNKNOWN";
> + }
> +
> + return "UNKNOWN";
> +}
> +
> +int main(int argc, char *argv[]) {
> + TALLOC_CTX *mem_ctx;
> + const char *filename = NULL;
> + const char *ca_file = NULL;
> + struct mscat_pkcs7 *cat_pkcs7;
> + struct mscat_ctl *msctl;
> + unsigned int member_count = 0;
> + unsigned int attribute_count = 0;
> + unsigned int i;
> + int rc;
> +
> + if (argc < 1) {
> + return -1;
> + }
> + filename = argv[1];
> +
> + if (filename == NULL || filename[0] == '\0') {
> + return -1;
> + }
> +
> + mem_ctx = talloc_init("dumpmscat");
> + if (mem_ctx == NULL) {
> + fprintf(stderr, "Failed to initialize talloc\n");
> + exit(1);
> + }
> +
> + /* READ MS ROOT CERTIFICATE */
> +
> + cat_pkcs7 = mscat_pkcs7_init(mem_ctx);
> + if (cat_pkcs7 == NULL) {
> + exit(1);
> + }
> +
> + rc = mscat_pkcs7_import_catfile(cat_pkcs7,
> + filename);
> + if (rc != 0) {
> + exit(1);
> + }
> +
> + if (argc >= 2) {
> + ca_file = argv[2];
> + }
> +
> + rc = mscat_pkcs7_verify(cat_pkcs7, ca_file);
> + if (rc != 0) {
> + printf("FAILED TO VERIFY CATALOG FILE!\n");
> + exit(1);
> + }
> + printf("CATALOG FILE VERIFIED!\n\n");
> +
> + msctl = mscat_ctl_init(mem_ctx);
> + if (msctl == NULL) {
> + exit(1);
> + }
> +
> + rc = mscat_ctl_import(msctl, cat_pkcs7);
> + if (rc != 0) {
> + exit(1);
> + }
> +
> + member_count = mscat_ctl_get_member_count(msctl);
> + printf("CATALOG MEMBER COUNT=%d\n", member_count);
> +
> + for (i = 0; i < member_count; i++) {
> + struct mscat_ctl_member *m;
> + size_t j;
> +
> + rc = mscat_ctl_get_member(msctl,
> + mem_ctx,
> + i + 1,
> + &m);
> + if (rc != 0) {
> + exit(1);
> + }
> +
> + printf("CATALOG MEMBER\n");
> + if (m->checksum.type == MSCAT_CHECKSUM_STRING) {
> + printf(" CHECKSUM: %s\n", m->checksum.string);
> + } else if (m->checksum.type == MSCAT_CHECKSUM_BLOB) {
> + printf(" CHECKSUM: ");
> + for (j = 0; j < m->checksum.size; j++) {
> + printf("%X", m->checksum.blob[j]);
> + }
> + printf("\n");
> + }
> + printf("\n");
> +
> + if (m->file.name != NULL) {
> + printf(" FILE: %s, FLAGS=0x%08x\n",
> + m->file.name,
> + m->file.flags);
> + }
> +
> + if (m->info.guid != NULL) {
> + printf(" GUID: %s, ID=0x%08x\n",
> + m->info.guid,
> + m->info.id);
> + }
> +
> + if (m->osattr.value != NULL) {
> + printf(" OSATTR: %s, FLAGS=0x%08x\n",
> + m->osattr.value,
> + m->osattr.flags);
> + }
> +
> + if (m->mac.type != MSCAT_MAC_UNKNOWN) {
> + printf(" MAC: %s, DIGEST: ",
> + mac_to_string(m->mac.type));
> + for (j = 0; j < m->mac.digest_size; j++) {
> + printf("%X", m->mac.digest[j]);
> + }
> + printf("\n");
> + }
> + printf("\n");
> + }
> + printf("\n");
> +
> + attribute_count = mscat_ctl_get_attribute_count(msctl);
> + printf("CATALOG ATTRIBUTE COUNT=%d\n", attribute_count);
> +
> + for (i = 0; i < attribute_count; i++) {
> + struct mscat_ctl_attribute *a;
> +
> + rc = mscat_ctl_get_attribute(msctl,
> + mem_ctx,
> + i + 1,
> + &a);
> + if (rc != 0) {
> + exit(1);
> + }
> +
> + printf(" NAME=%s, FLAGS=0x%08x, VALUE=%s\n",
> + a->name,
> + a->flags,
> + a->value);
> + }
> + talloc_free(mem_ctx);
> + return 0;
> +}
> diff --git a/lib/mscat/mscat.asn b/lib/mscat/mscat.asn
> new file mode 100644
> index 00000000000..a4bdd057793
> --- /dev/null
> +++ b/lib/mscat/mscat.asn
> @@ -0,0 +1,136 @@
> +--
> +-- ASN.1 Description for Microsoft Catalog Files
> +--
> +-- Copyright 2016 Andreas Schneider <asn at samba.org>
> +-- Copyright 2016 Nikos Mavrogiannopoulos <nmav at redhat.com>
> +--
> +-- This program is free software: you can redistribute it and/or modify
> +-- it under the terms of the GNU Lesser General Public License as published
> +-- by the Free Software Foundation, either version 3 of the License, or
> +-- (at your option) any later version.
> +--
> +-- This program is distributed in the hope that it will be useful,
> +-- but WITHOUT ANY WARRANTY; without even the implied warranty of
> +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> +-- GNU Lesser General Public License for more details.
> +--
> +-- You should have received a copy of the GNU Lesser General Public License
> +-- along with this program. If not, see <http://www.gnu.org/licenses/>.
> +--
> +CATALOG {}
> +DEFINITIONS IMPLICIT TAGS ::= -- assuming implicit tags, should try explicit too
> +
> +BEGIN
> +
> +-- CATALOG_NAME_VALUE
> +CatalogNameValue ::= SEQUENCE { -- 180
> + name BMPString,
> + flags INTEGER, -- 10010001
> + value OCTET STRING -- UTF-16-LE
> +}
> +
> +-- CATALOG_MEMBER_INFO
> +CatalogMemberInfo ::= SEQUENCE {
> + name BMPString,
> + id INTEGER -- 0200
> +}
> +
> +CatalogMemberInfo2 ::= SEQUENCE {
> + memId OBJECT IDENTIFIER,
> + unknown SET OF SpcLink
> +}
> +
> +-- SPC_INDIRECT_DATA
> +SpcIndirectData ::= SEQUENCE {
> + data SpcAttributeTypeAndOptionalValue,
> + messageDigest DigestInfo
> +}
> +
> +SpcAttributeTypeAndOptionalValue ::= SEQUENCE {
> + type OBJECT IDENTIFIER,
> + value ANY DEFINED BY type OPTIONAL
> +}
> +
> +DigestInfo ::= SEQUENCE {
> + digestAlgorithm AlgorithmIdentifier,
> + digest OCTET STRING
> +}
> +
> +AlgorithmIdentifier ::= SEQUENCE {
> + algorithm OBJECT IDENTIFIER,
> + parameters ANY DEFINED BY algorithm OPTIONAL
> + -- contains a value of the type
> +}
> +
> +-- SPC_PE_IMAGE_DATA
> +SpcPEImageData ::= SEQUENCE {
> + flags SpcPeImageFlags DEFAULT includeResources,
> + link [0] EXPLICIT SpcLink OPTIONAL
> +}
> +
> +SpcPeImageFlags ::= BIT STRING {
> + includeResources (0),
> + includeDebugInfo (1),
> + includeImportAddressTable (2)
> +}
> +
> +SpcLink ::= CHOICE {
> + url [0] IMPLICIT IA5String,
> + moniker [1] IMPLICIT SpcSerializedObject,
> + file [2] EXPLICIT SpcString
> +}
> +
> +SpcSerializedObject ::= SEQUENCE {
> + classId OCTET STRING, -- GUID
> + data OCTET STRING -- Binary structure
> +}
> +
> +SpcString ::= CHOICE {
> + unicode [0] IMPLICIT BMPString,
> + ascii [1] IMPLICIT IA5String
> +}
> +
> +-- SPC_IMAGE_DATA_FILE
> +SpcImageDataFile ::= SEQUENCE {
> + flags BIT STRING,
> + file SpcLink
> +}
> +
> +-----------------------------------------------------------
> +-- CERT_TRUST_LIST STRUCTURE
> +-----------------------------------------------------------
> +
> +CatalogListId ::= SEQUENCE {
> + oid OBJECT IDENTIFIER
> +}
> +
> +CatalogListMemberId ::= SEQUENCE {
> + oid OBJECT IDENTIFIER,
> + optional NULL
> +}
> +
> +MemberAttribute ::= SEQUENCE {
> + contentType OBJECT IDENTIFIER,
> + content SET OF ANY DEFINED BY contentType
> +}
> +
> +CatalogListMember ::= SEQUENCE {
> + checksum OCTET STRING, -- The member checksum (e.g. SHA1)
> + attributes SET OF MemberAttribute OPTIONAL
> +}
> +
> +CatalogAttribute ::= SEQUENCE {
> + dataId OBJECT IDENTIFIER,
> + encapsulated_data OCTET STRING -- encapsulates CatNameValue or SpcPeImageData
> +}
> +
> +CertTrustList ::= SEQUENCE {
> + catalogListId CatalogListId,
> + unknownString OCTET STRING, -- 16 bytes MD5 hash?
> + trustUtcTime UTCTime,
> + catalogListMemberId CatalogListMemberId,
> + members SEQUENCE OF CatalogListMember,
> + attributes [0] EXPLICIT SEQUENCE OF CatalogAttribute OPTIONAL
> +}
> +
> +END
> diff --git a/lib/mscat/mscat.h b/lib/mscat/mscat.h
> new file mode 100644
> index 00000000000..fbf60ffb117
> --- /dev/null
> +++ b/lib/mscat/mscat.h
> @@ -0,0 +1,105 @@
> +/*
> + * Copyright (c) 2016 Andreas Schneider <asn at samba.org>
> + *
> + * This program is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, either version 3 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef _MSCAT_H
> +#define _MSCAT_H
> +
> +#include <stdbool.h>
> +#include <talloc.h>
> +#include <gnutls/pkcs7.h>
> +#include <libtasn1.h>
> +
> +enum mscat_mac_algorithm {
> + MSCAT_MAC_UNKNOWN,
> + MSCAT_MAC_NULL,
> + MSCAT_MAC_MD5,
> + MSCAT_MAC_SHA1,
> + MSCAT_MAC_SHA256,
> + MSCAT_MAC_SHA512
> +};
> +
> +struct mscat_pkcs7;
> +
> +struct mscat_pkcs7 *mscat_pkcs7_init(TALLOC_CTX *mem_ctx);
> +
> +int mscat_pkcs7_import_catfile(struct mscat_pkcs7 *mp7,
> + const char *catfile);
> +
> +int mscat_pkcs7_verify(struct mscat_pkcs7 *mp7,
> + const char *ca_file);
> +
> +struct mscat_ctl;
> +
> +struct mscat_ctl *mscat_ctl_init(TALLOC_CTX *mem_ctx);
> +
> +int mscat_ctl_import(struct mscat_ctl *ctl,
> + struct mscat_pkcs7 *pkcs7);
> +
> +int mscat_ctl_get_member_count(struct mscat_ctl *ctl);
> +
> +enum mscat_checksum_type {
> + MSCAT_CHECKSUM_STRING = 1,
> + MSCAT_CHECKSUM_BLOB
> +};
> +
> +struct mscat_ctl_member {
> + struct {
> + enum mscat_checksum_type type;
> + union {
> + const char *string;
> + uint8_t *blob;
> + };
> + size_t size;
> + } checksum;
> + struct {
> + const char *name;
> + uint32_t flags;
> + } file;
> + struct {
> + const char *value;
> + uint32_t flags;
> + } osattr;
> + struct {
> + const char *guid;
> + uint32_t id;
> + } info;
> + struct {
> + enum mscat_mac_algorithm type;
> + uint8_t *digest;
> + size_t digest_size;
> + } mac;
> +};
> +
> +int mscat_ctl_get_member(struct mscat_ctl *ctl,
> + TALLOC_CTX *mem_ctx,
> + unsigned int idx,
> + struct mscat_ctl_member **member);
> +
> +int mscat_ctl_get_attribute_count(struct mscat_ctl *ctl);
> +
> +struct mscat_ctl_attribute {
> + const char *name;
> + uint32_t flags;
> + const char *value;
> +};
> +
> +int mscat_ctl_get_attribute(struct mscat_ctl *ctl,
> + TALLOC_CTX *mem_ctx,
> + unsigned int idx,
> + struct mscat_ctl_attribute **pattribute);
> +
> +#endif /* _MSCAT_H */
> diff --git a/lib/mscat/mscat_ctl.c b/lib/mscat/mscat_ctl.c
> new file mode 100644
> index 00000000000..972922c4f75
> --- /dev/null
> +++ b/lib/mscat/mscat_ctl.c
> @@ -0,0 +1,1194 @@
> +/*
> + * Copyright (c) 2016 Andreas Schneider <asn at samba.org>
> + *
> + * This program is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, either version 3 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <errno.h>
> +#include <string.h>
> +#include <stdint.h>
> +
> +#include <util/debug.h>
> +#include <util/byteorder.h>
> +#include <util/data_blob.h>
> +#include <charset.h>
> +
> +#include "mscat.h"
> +#include "mscat_private.h"
> +
> +#define ASN1_NULL_DATA "\x05\x00"
> +#define ASN1_NULL_DATA_SIZE 2
> +
> +#define HASH_SHA1_OBJID "1.3.14.3.2.26"
> +#define HASH_SHA256_OBJID "2.16.840.1.101.3.4.2.1"
> +#define HASH_SHA512_OBJID "2.16.840.1.101.3.4.2.3"
> +
> +#define SPC_INDIRECT_DATA_OBJID "1.3.6.1.4.1.311.2.1.4"
> +#define SPC_PE_IMAGE_DATA_OBJID "1.3.6.1.4.1.311.2.1.15"
> +
> +#define CATALOG_LIST_OBJOID "1.3.6.1.4.1.311.12.1.1"
> +#define CATALOG_LIST_MEMBER_OBJOID "1.3.6.1.4.1.311.12.1.2"
> +#define CATALOG_LIST_MEMBER_V2_OBJOID "1.3.6.1.4.1.311.12.1.3"
> +
> +#define CAT_NAME_VALUE_OBJID "1.3.6.1.4.1.311.12.2.1"
> +#define CAT_MEMBERINFO_OBJID "1.3.6.1.4.1.311.12.2.2"
> +
> +extern const asn1_static_node mscat_asn1_tab[];
> +
> +struct mscat_ctl {
> + int version;
> + ASN1_TYPE asn1_desc;
> + ASN1_TYPE tree_ctl;
> + gnutls_datum_t raw_ctl;
> +};
> +
> +static char *mscat_asn1_get_oid(TALLOC_CTX *mem_ctx,
> + asn1_node root,
> + const char *oid_name)
> +{
> + char oid_str[32] = {0};
> + int oid_len = sizeof(oid_str);
> + int rc;
> +
> + rc = asn1_read_value(root,
> + oid_name,
> + oid_str,
> + &oid_len);
> + if (rc != ASN1_SUCCESS) {
> + DBG_ERR("Failed to read value '%s': %s\n",
> + oid_name,
> + asn1_strerror(rc));
> + return NULL;
> + }
> +
> + return talloc_strndup(mem_ctx, oid_str, oid_len);
> +}
> +
> +static bool mscat_asn1_oid_equal(const char *o1, const char *o2)
> +{
> + int cmp;
> +
> + cmp = strcmp(o1, o2);
> + if (cmp != 0) {
> + return false;
> + }
> +
> + return true;
> +}
> +
> +static int mscat_asn1_read_value(TALLOC_CTX *mem_ctx,
> + asn1_node root,
> + const char *name,
> + DATA_BLOB *blob)
> +{
> + DATA_BLOB tmp = data_blob_null;
> + unsigned int etype = ASN1_ETYPE_INVALID;
> + int len = 0;
> + int rc;
> +
> + rc = asn1_read_value_type(root, name, NULL, &len, &etype);
> + if (rc != ASN1_SUCCESS) {
> + return rc;
> + }
> +
> + if (etype == ASN1_ETYPE_BIT_STRING) {
> + if (len + 7 < len) {
> + return -1;
> + }
> + len = (len + 7) / 8;
> + }
> +
> + if (len == 0) {
> + *blob = data_blob_null;
> + return 0;
> + }
> +
> + if (len + 1 < len) {
> + return -1;
> + }
> + tmp = data_blob_talloc_zero(mem_ctx, len + 1);
> + if (tmp.data == NULL) {
> + return -1;
> + }
> +
> + rc = asn1_read_value(root,
> + name,
> + tmp.data,
> + &len);
> + if (rc != ASN1_SUCCESS) {
> + data_blob_free(&tmp);
> + return rc;
> + }
> +
> + if (etype == ASN1_ETYPE_BIT_STRING) {
> + if (len + 7 < len) {
> + return -1;
> + }
> + len = (len + 7) / 8;
> + }
> + tmp.length = len;
> +
> + *blob = tmp;
> +
> + return 0;
> +}
> +
> +static int mscat_ctl_cleanup(struct mscat_ctl *ctl)
> +{
> + if (ctl->asn1_desc != ASN1_TYPE_EMPTY) {
> + asn1_delete_structure(&ctl->asn1_desc);
> + }
> +
> + return 0;
> +}
> +
> +struct mscat_ctl *mscat_ctl_init(TALLOC_CTX *mem_ctx)
> +{
> + char error_string[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = {0};
> + struct mscat_ctl *cat_ctl = NULL;
> + int rc;
> +
> + cat_ctl = talloc_zero(mem_ctx, struct mscat_ctl);
> + if (cat_ctl == NULL) {
> + return NULL;
> + }
> + talloc_set_destructor(cat_ctl, mscat_ctl_cleanup);
> +
> + cat_ctl->asn1_desc = ASN1_TYPE_EMPTY;
> + cat_ctl->tree_ctl = ASN1_TYPE_EMPTY;
> +
> + rc = asn1_array2tree(mscat_asn1_tab,
> + &cat_ctl->asn1_desc,
> + error_string);
> + if (rc != ASN1_SUCCESS) {
> + talloc_free(cat_ctl);
> + DBG_ERR("Failed to create parser tree: %s - %s\n",
> + asn1_strerror(rc),
> + error_string);
> + return NULL;
> + }
> +
> + return cat_ctl;
> +}
> +
> +int mscat_ctl_import(struct mscat_ctl *ctl,
> + struct mscat_pkcs7 *pkcs7)
> +{
> + char error_string[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = {0};
> + TALLOC_CTX *tmp_ctx = NULL;
> + char *oid;
> + bool ok;
> + int rc;
> +
> + rc = gnutls_pkcs7_get_embedded_data(pkcs7->c,
> + GNUTLS_PKCS7_EDATA_GET_RAW,
> + &ctl->raw_ctl);
> + if (rc != GNUTLS_E_SUCCESS) {
> + DBG_ERR("Failed to get embedded data from pkcs7: %s\n",
> + gnutls_strerror(rc));
> + return -1;
> + }
> +
> + rc = asn1_create_element(ctl->asn1_desc,
> + "CATALOG.CertTrustList",
> + &ctl->tree_ctl);
> + if (rc != ASN1_SUCCESS) {
> + DBG_ERR("Failed to create CertTrustList ASN.1 element - %s\n",
> + asn1_strerror(rc));
> + return -1;
> + }
> +
> + rc = asn1_der_decoding(&ctl->tree_ctl,
> + ctl->raw_ctl.data,
> + ctl->raw_ctl.size,
> + error_string);
> + if (rc != ASN1_SUCCESS) {
> + DBG_ERR("Failed to parse ASN.1 CertTrustList: %s - %s\n",
> + asn1_strerror(rc),
> + error_string);
> + return -1;
> + }
> +
> + tmp_ctx = talloc_new(ctl);
> + if (tmp_ctx == NULL) {
> + return -1;
> + }
> +
> + oid = mscat_asn1_get_oid(tmp_ctx,
> + ctl->tree_ctl,
> + "catalogListId.oid");
> + if (oid == NULL) {
> + rc = -1;
> + goto done;
> + }
> +
> + ok = mscat_asn1_oid_equal(oid, CATALOG_LIST_OBJOID);
> + if (!ok) {
> + DBG_ERR("Invalid oid (%s), expected CATALOG_LIST_OBJOID",
> + oid);
> + rc = -1;
> + goto done;
> + }
> + talloc_free(oid);
> +
> + oid = mscat_asn1_get_oid(tmp_ctx,
> + ctl->tree_ctl,
> + "catalogListMemberId.oid");
> + if (oid == NULL) {
> + rc = -1;
> + goto done;
> + }
> +
> + ok = mscat_asn1_oid_equal(oid, CATALOG_LIST_MEMBER_V2_OBJOID);
> + if (ok) {
> + ctl->version = 2;
> + } else {
> + ok = mscat_asn1_oid_equal(oid, CATALOG_LIST_MEMBER_OBJOID);
> + if (ok) {
> + ctl->version = 1;
> + } else {
> + DBG_ERR("Invalid oid (%s), expected "
> + "CATALOG_LIST_MEMBER_OBJOID",
> + oid);
> + rc = -1;
> + goto done;
> + }
> + }
> +
> + rc = 0;
> +done:
> + talloc_free(tmp_ctx);
> + return rc;
> +}
> +
> +static int ctl_get_member_checksum_string(struct mscat_ctl *ctl,
> + TALLOC_CTX *mem_ctx,
> + unsigned int idx,
> + const char **pchecksum,
> + size_t *pchecksum_size)
> +{
> + TALLOC_CTX *tmp_ctx;
> + DATA_BLOB chksum_ucs2 = data_blob_null;
> + size_t converted_size = 0;
> + char *checksum = NULL;
> + char *element = NULL;
> + int rc = -1;
> + bool ok;
> +
> + tmp_ctx = talloc_new(mem_ctx);
> + if (tmp_ctx == NULL) {
> + return -1;
> + }
> +
> + element = talloc_asprintf(tmp_ctx,
> + "members.?%u.checksum",
> + idx);
> + if (element == NULL) {
> + goto done;
> + }
> +
> + rc = mscat_asn1_read_value(tmp_ctx,
> + ctl->tree_ctl,
> + element,
> + &chksum_ucs2);
> + talloc_free(element);
> + if (rc != 0) {
> + goto done;
> + }
> +
> + ok = convert_string_talloc(mem_ctx,
> + CH_UTF16LE,
> + CH_UNIX,
> + chksum_ucs2.data,
> + chksum_ucs2.length,
> + (void **)&checksum,
> + &converted_size);
> + if (!ok) {
> + rc = -1;
> + goto done;
> + }
> +
> + *pchecksum_size = strlen(checksum) + 1;
> + *pchecksum = talloc_move(mem_ctx, &checksum);
> +
> + rc = 0;
> +done:
> + talloc_free(tmp_ctx);
> + return rc;
> +}
> +
> +static int ctl_get_member_checksum_blob(struct mscat_ctl *ctl,
> + TALLOC_CTX *mem_ctx,
> + unsigned int idx,
> + uint8_t **pchecksum,
> + size_t *pchecksum_size)
> +{
> + TALLOC_CTX *tmp_ctx;
> + DATA_BLOB chksum = data_blob_null;
> + char *element = NULL;
> + int rc = -1;
> +
> + tmp_ctx = talloc_new(mem_ctx);
> + if (tmp_ctx == NULL) {
> + return -1;
> + }
> +
> + element = talloc_asprintf(tmp_ctx,
> + "members.?%u.checksum",
> + idx);
> + if (element == NULL) {
> + goto done;
> + }
> +
> + rc = mscat_asn1_read_value(tmp_ctx,
> + ctl->tree_ctl,
> + element,
> + &chksum);
> + talloc_free(element);
> + if (rc != 0) {
> + goto done;
> + }
> +
> + *pchecksum = talloc_move(mem_ctx, &chksum.data);
> + *pchecksum_size = chksum.length;
> +
> + rc = 0;
> +done:
> + talloc_free(tmp_ctx);
> + return rc;
> +}
> +
> +static int ctl_parse_name_value(struct mscat_ctl *ctl,
> + TALLOC_CTX *mem_ctx,
> + DATA_BLOB *content,
> + char **pname,
> + uint32_t *pflags,
> + char **pvalue)
> +{
> + char error_string[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = {0};
> + ASN1_TYPE name_value = ASN1_TYPE_EMPTY;
> + TALLOC_CTX *tmp_ctx;
> + DATA_BLOB name_blob = data_blob_null;
> + DATA_BLOB flags_blob = data_blob_null;
> + DATA_BLOB value_blob = data_blob_null;
> + size_t converted_size = 0;
> + bool ok;
> + int rc;
> +
> + tmp_ctx = talloc_new(mem_ctx);
> + if (tmp_ctx == NULL) {
> + return -1;
> + }
> +
> + rc = asn1_create_element(ctl->asn1_desc,
> + "CATALOG.CatalogNameValue",
> + &name_value);
> + if (rc != ASN1_SUCCESS) {
> + DBG_ERR("Failed to create element for "
> + "CATALOG.CatalogNameValue: %s\n",
> + asn1_strerror(rc));
> + goto done;
> + }
> +
> + rc = asn1_der_decoding(&name_value,
> + content->data,
> + content->length,
> + error_string);
> + if (rc != ASN1_SUCCESS) {
> + DBG_ERR("Failed to decode CATALOG.CatalogNameValue: %s - %s",
> + asn1_strerror(rc),
> + error_string);
> + goto done;
> + }
> +
> + rc = mscat_asn1_read_value(mem_ctx,
> + name_value,
> + "name",
> + &name_blob);
> + if (rc != ASN1_SUCCESS) {
> + DBG_ERR("Failed to read 'name': %s\n",
> + asn1_strerror(rc));
> + goto done;
> + }
> +
> + rc = mscat_asn1_read_value(mem_ctx,
> + name_value,
> + "flags",
> + &flags_blob);
> + if (rc != ASN1_SUCCESS) {
> + DBG_ERR("Failed to read 'flags': %s\n",
> + asn1_strerror(rc));
> + goto done;
> + }
> +
> + rc = mscat_asn1_read_value(mem_ctx,
> + name_value,
> + "value",
> + &value_blob);
> + if (rc != ASN1_SUCCESS) {
> + DBG_ERR("Failed to read 'value': %s\n",
> + asn1_strerror(rc));
> + goto done;
> + }
> +
> + ok = convert_string_talloc(mem_ctx,
> + CH_UTF16BE,
> + CH_UNIX,
> + name_blob.data,
> + name_blob.length,
> + (void **)pname,
> + &converted_size);
> + if (!ok) {
> + rc = ASN1_MEM_ERROR;
> + goto done;
> + }
> +
> + *pflags = RIVAL(flags_blob.data, 0);
> +
> + ok = convert_string_talloc(mem_ctx,
> + CH_UTF16LE,
> + CH_UNIX,
> + value_blob.data,
> + value_blob.length,
> + (void **)pvalue,
> + &converted_size);
> + if (!ok) {
> + rc = ASN1_MEM_ERROR;
> + goto done;
> + }
> +
> + rc = 0;
> +done:
> + talloc_free(tmp_ctx);
> + return rc;
> +}
> +
> +static int ctl_parse_member_info(struct mscat_ctl *ctl,
> + TALLOC_CTX *mem_ctx,
> + DATA_BLOB *content,
> + char **pname,
> + uint32_t *pid)
> +{
> + char error_string[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = {0};
> + ASN1_TYPE member_info = ASN1_TYPE_EMPTY;
> + TALLOC_CTX *tmp_ctx;
> + DATA_BLOB name_blob = data_blob_null;
> + DATA_BLOB id_blob = data_blob_null;
> + size_t converted_size = 0;
> + bool ok;
> + int rc;
> +
> + tmp_ctx = talloc_new(mem_ctx);
> + if (tmp_ctx == NULL) {
> + return -1;
> + }
> +
> + rc = asn1_create_element(ctl->asn1_desc,
> + "CATALOG.CatalogMemberInfo",
> + &member_info);
> + if (rc != ASN1_SUCCESS) {
> + DBG_ERR("Failed to create element for "
> + "CATALOG.CatalogMemberInfo: %s\n",
> + asn1_strerror(rc));
> + goto done;
> + }
> +
> + rc = asn1_der_decoding(&member_info,
> + content->data,
> + content->length,
> + error_string);
> + if (rc != ASN1_SUCCESS) {
> + DBG_ERR("Failed to decode CATALOG.CatalogMemberInfo: %s - %s",
> + asn1_strerror(rc),
> + error_string);
> + goto done;
> + }
> +
> + rc = mscat_asn1_read_value(mem_ctx,
> + member_info,
> + "name",
> + &name_blob);
> + if (rc != ASN1_SUCCESS) {
> + DBG_ERR("Failed to read 'name': %s\n",
> + asn1_strerror(rc));
> + goto done;
> + }
> +
> + rc = mscat_asn1_read_value(mem_ctx,
> + member_info,
> + "id",
> + &id_blob);
> + if (rc != ASN1_SUCCESS) {
> + DBG_ERR("Failed to read 'id': %s\n",
> + asn1_strerror(rc));
> + goto done;
> + }
> +
> + ok = convert_string_talloc(mem_ctx,
> + CH_UTF16BE,
> + CH_UNIX,
> + name_blob.data,
> + name_blob.length,
> + (void **)pname,
> + &converted_size);
> + if (!ok) {
> + rc = ASN1_MEM_ERROR;
> + goto done;
> + }
> +
> + *pid = RSVAL(id_blob.data, 0);
> +
> + rc = 0;
> +done:
> + talloc_free(tmp_ctx);
> + return rc;
> +}
> +
> +
> +static int ctl_spc_pe_image_data(struct mscat_ctl *ctl,
> + TALLOC_CTX *mem_ctx,
> + DATA_BLOB *content,
> + char **pfile)
> +{
> + char error_string[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = {0};
> + ASN1_TYPE spc_pe_image_data = ASN1_TYPE_EMPTY;
> + DATA_BLOB flags_blob = data_blob_null;
> + DATA_BLOB choice_blob = data_blob_null;
> + char *file = NULL;
> + TALLOC_CTX *tmp_ctx;
> + int cmp;
> + int rc;
> +
> + tmp_ctx = talloc_new(mem_ctx);
> + if (tmp_ctx == NULL) {
> + return -1;
> + }
> +
> + rc = asn1_create_element(ctl->asn1_desc,
> + "CATALOG.SpcPEImageData",
> + &spc_pe_image_data);
> + if (rc != ASN1_SUCCESS) {
> + DBG_ERR("Failed to create element for "
> + "CATALOG.SpcPEImageData: %s\n",
> + asn1_strerror(rc));
> + goto done;
> + }
> +
> + rc = asn1_der_decoding(&spc_pe_image_data,
> + content->data,
> + content->length,
> + error_string);
> + if (rc != ASN1_SUCCESS) {
> + DBG_ERR("Failed to decode CATALOG.SpcPEImageData: %s - %s",
> + asn1_strerror(rc),
> + error_string);
> + goto done;
> + }
> +
> + rc = mscat_asn1_read_value(tmp_ctx,
> + spc_pe_image_data,
> + "flags",
> + &flags_blob);
> + if (rc == ASN1_SUCCESS) {
> + uint32_t flags = RIVAL(flags_blob.data, 0);
> +
> + DBG_ERR(">>> SPC_PE_IMAGE_DATA FLAGS=0x%08x",
> + flags);
> + } else {
> + DBG_ERR("Failed to parse 'flags' in CATALOG.SpcPEImageData - %s",
> + asn1_strerror(rc));
> + goto done;
> + }
> +
> + rc = mscat_asn1_read_value(tmp_ctx,
> + spc_pe_image_data,
> + "link",
> + &choice_blob);
> + if (rc != ASN1_SUCCESS) {
> + DBG_ERR("Failed to parse 'link' in CATALOG.SpcPEImageData - %s",
> + asn1_strerror(rc));
> + goto done;
> + }
> +
> + cmp = strncmp((char *)choice_blob.data, "url", choice_blob.length);
> + if (cmp == 0) {
> + /* Never seen in a printer catalog file yet */
> + DBG_INFO("Please report a Samba bug and attach the catalog "
> + "file\n");
> + }
> +
> + cmp = strncmp((char *)choice_blob.data, "moniker", choice_blob.length);
> + if (cmp == 0) {
> + /* Never seen in a printer catalog file yet */
> + DBG_INFO("Please report a Samba bug and attach the catalog "
> + "file\n");
> + }
> +
> + cmp = strncmp((char *)choice_blob.data, "file", choice_blob.length);
> + if (cmp == 0) {
> + DATA_BLOB file_blob;
> + char *link;
> +
> + rc = mscat_asn1_read_value(tmp_ctx,
> + spc_pe_image_data,
> + "link.file",
> + &choice_blob);
> + if (rc != ASN1_SUCCESS) {
> + goto done;
> + }
> +
> + link = talloc_asprintf(tmp_ctx, "link.file.%s", (char *)choice_blob.data);
> + if (link == NULL) {
> + rc = -1;
> + goto done;
> + }
> +
> + rc = mscat_asn1_read_value(tmp_ctx,
> + spc_pe_image_data,
> + link,
> + &file_blob);
> + if (rc != ASN1_SUCCESS) {
> + DBG_ERR("Failed to read '%s' - %s",
> + link,
> + asn1_strerror(rc));
> + rc = -1;
> + goto done;
> + }
> +
> + cmp = strncmp((char *)choice_blob.data, "unicode", choice_blob.length);
> + if (cmp == 0) {
> + size_t converted_size = 0;
> + bool ok;
> +
> + ok = convert_string_talloc(tmp_ctx,
> + CH_UTF16BE,
> + CH_UNIX,
> + file_blob.data,
> + file_blob.length,
> + (void **)&file,
> + &converted_size);
> + if (!ok) {
> + rc = -1;
> + goto done;
> + }
> + }
> +
> + cmp = strncmp((char *)choice_blob.data, "ascii", choice_blob.length);
> + if (cmp == 0) {
> + file = talloc_strndup(tmp_ctx,
> + (char *)file_blob.data,
> + file_blob.length);
> + if (file == NULL) {
> + rc = -1;
> + goto done;
> + }
> + }
> + }
> +
> + if (file != NULL) {
> + *pfile = talloc_move(mem_ctx, &file);
> + }
> +
> + rc = 0;
> +done:
> + talloc_free(tmp_ctx);
> + return rc;
> +}
> +
> +static int ctl_spc_indirect_data(struct mscat_ctl *ctl,
> + TALLOC_CTX *mem_ctx,
> + DATA_BLOB *content,
> + enum mscat_mac_algorithm *pmac_algorithm,
> + uint8_t **pdigest,
> + size_t *pdigest_size)
> +{
> + char error_string[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = {0};
> + ASN1_TYPE spc_indirect_data = ASN1_TYPE_EMPTY;
> + TALLOC_CTX *tmp_ctx;
> + enum mscat_mac_algorithm mac_algorithm = MSCAT_MAC_UNKNOWN;
> + const char *oid = NULL;
> + DATA_BLOB data_value_blob = data_blob_null;
> + DATA_BLOB digest_parameters_blob = data_blob_null;
> + DATA_BLOB digest_blob = data_blob_null;
> + bool ok;
> + int rc;
> +
> + tmp_ctx = talloc_new(mem_ctx);
> + if (tmp_ctx == NULL) {
> + return -1;
> + }
> +
> + rc = asn1_create_element(ctl->asn1_desc,
> + "CATALOG.SpcIndirectData",
> + &spc_indirect_data);
> + if (rc != ASN1_SUCCESS) {
> + DBG_ERR("Failed to create element for "
> + "CATALOG.SpcIndirectData: %s\n",
> + asn1_strerror(rc));
> + goto done;
> + }
> +
> + rc = asn1_der_decoding(&spc_indirect_data,
> + content->data,
> + content->length,
> + error_string);
> + if (rc != ASN1_SUCCESS) {
> + DBG_ERR("Failed to decode CATALOG.SpcIndirectData: %s - %s",
> + asn1_strerror(rc),
> + error_string);
> + goto done;
> + }
> +
> + oid = mscat_asn1_get_oid(tmp_ctx,
> + spc_indirect_data,
> + "data.type");
> + if (oid == NULL) {
> + goto done;
> + }
> +
> + rc = mscat_asn1_read_value(tmp_ctx,
> + spc_indirect_data,
> + "data.value",
> + &data_value_blob);
> + if (rc != ASN1_SUCCESS) {
> + DBG_ERR("Failed to find data.value in SpcIndirectData: %s\n",
> + asn1_strerror(rc));
> + goto done;
> + }
> +
> + ok = mscat_asn1_oid_equal(oid, SPC_PE_IMAGE_DATA_OBJID);
> + if (ok) {
> + char *file = NULL;
> +
> + rc = ctl_spc_pe_image_data(ctl,
> + tmp_ctx,
> + &data_value_blob,
> + &file);
> + if (rc != 0) {
> + goto done;
> + }
> +
> + /* Just returns <<<Obsolete>>> as file */
> + DBG_NOTICE(">>> LINK: %s",
> + file);
> + }
> +
> + oid = mscat_asn1_get_oid(tmp_ctx,
> + spc_indirect_data,
> + "messageDigest.digestAlgorithm.algorithm");
> + if (oid == NULL) {
> + goto done;
> + }
> +
> + rc = mscat_asn1_read_value(tmp_ctx,
> + spc_indirect_data,
> + "messageDigest.digestAlgorithm.parameters",
> + &digest_parameters_blob);
> + if (rc == ASN1_SUCCESS) {
> + /* Make sure we don't have garbage */
> + int cmp;
> +
> + if (digest_parameters_blob.length != ASN1_NULL_DATA_SIZE) {
> + rc = -1;
> + goto done;
> + }
> + cmp = memcmp(digest_parameters_blob.data,
> + ASN1_NULL_DATA,
> + digest_parameters_blob.length);
> + if (cmp != 0) {
> + rc = -1;
> + goto done;
> + }
> + } else if (rc != ASN1_ELEMENT_NOT_FOUND) {
> + DBG_ERR("Failed to read 'messageDigest.digestAlgorithm.parameters': %s\n",
> + asn1_strerror(rc));
> + goto done;
> + }
> +
> + ok = mscat_asn1_oid_equal(oid, HASH_SHA1_OBJID);
> + if (ok) {
> + mac_algorithm = MSCAT_MAC_SHA1;
> + }
> +
> + ok = mscat_asn1_oid_equal(oid, HASH_SHA256_OBJID);
> + if (ok) {
> + mac_algorithm = MSCAT_MAC_SHA256;
> + }
> +
> + if (mac_algorithm != MSCAT_MAC_UNKNOWN &&
> + mac_algorithm != MSCAT_MAC_NULL) {
> + rc = mscat_asn1_read_value(tmp_ctx,
> + spc_indirect_data,
> + "messageDigest.digest",
> + &digest_blob);
> + if (rc != ASN1_SUCCESS) {
> + DBG_ERR("Failed to find messageDigest.digest in "
> + "SpcIndirectData: %s\n",
> + asn1_strerror(rc));
> + goto done;
> + }
> + }
> +
> + *pmac_algorithm = mac_algorithm;
> + *pdigest = talloc_move(mem_ctx, &digest_blob.data);
> + *pdigest_size = digest_blob.length;
> +
> + rc = 0;
> +done:
> + talloc_free(tmp_ctx);
> + return rc;
> +}
> +
> +static int ctl_get_member_attributes(struct mscat_ctl *ctl,
> + TALLOC_CTX *mem_ctx,
> + unsigned int idx,
> + struct mscat_ctl_member *m)
> +{
> + TALLOC_CTX *tmp_ctx;
> + char *el1 = NULL;
> + int count = 0;
> + int i;
> + int rc = -1;
> +
> + tmp_ctx = talloc_new(mem_ctx);
> + if (tmp_ctx == NULL) {
> + return -1;
> + }
> +
> + el1 = talloc_asprintf(tmp_ctx,
> + "members.?%u.attributes",
> + idx);
> + if (el1 == NULL) {
> + goto done;
> + }
> +
> + rc = asn1_number_of_elements(ctl->tree_ctl,
> + el1,
> + &count);
> + if (rc != ASN1_SUCCESS) {
> + goto done;
> + }
> +
> + for (i = 0; i < count; i++) {
> + int content_start = 0;
> + int content_end = 0;
> + size_t content_len;
> + DATA_BLOB content;
> + char *el2;
> + char *oid;
> + bool ok;
> +
> + el2 = talloc_asprintf(tmp_ctx,
> + "%s.?%d.contentType",
> + el1,
> + i + 1);
> + if (el2 == NULL) {
> + rc = -1;
> + goto done;
> + }
> +
> + oid = mscat_asn1_get_oid(tmp_ctx,
> + ctl->tree_ctl,
> + el2);
> + talloc_free(el2);
> + if (oid == NULL) {
> + rc = -1;
> + goto done;
> + }
> +
> + /* FIXME Looks like this is always 1 */
> + el2 = talloc_asprintf(tmp_ctx,
> + "%s.?%d.content.?1",
> + el1,
> + i + 1);
> + if (el2 == NULL) {
> + rc = -1;
> + goto done;
> + }
> +
> + DBG_DEBUG("Decode element (startEnd) %s",
> + el2);
> +
> + rc = asn1_der_decoding_startEnd(ctl->tree_ctl,
> + ctl->raw_ctl.data,
> + ctl->raw_ctl.size,
> + el2,
> + &content_start,
> + &content_end);
> + if (rc != ASN1_SUCCESS) {
> + goto done;
> + }
> + if (content_start < content_end) {
> + goto done;
> + }
> + content_len = content_end - content_start + 1;
> +
> + DBG_DEBUG("Content data_blob length: %zu",
> + content_len);
> +
> + content = data_blob_talloc_zero(tmp_ctx, content_len);
> + if (content.data == NULL) {
> + rc = -1;
> + goto done;
> + }
> + memcpy(content.data,
> + &ctl->raw_ctl.data[content_start],
> + content_len);
> +
> + ok = mscat_asn1_oid_equal(oid, CAT_NAME_VALUE_OBJID);
> + if (ok) {
> + char *name;
> + uint32_t flags;
> + char *value;
> + int cmp;
> +
> + rc = ctl_parse_name_value(ctl,
> + tmp_ctx,
> + &content,
> + &name,
> + &flags,
> + &value);
> + if (rc != 0) {
> + goto done;
> + }
> +
> + DBG_DEBUG("Parsed NameValue: name=%s, flags=%u, value=%s",
> + name,
> + flags,
> + value);
> +
> + cmp = strcmp(name, "File");
> + if (cmp == 0) {
> + m->file.name = talloc_move(m, &value);
> + m->file.flags = flags;
> +
> + continue;
> + }
> +
> + cmp = strcmp(name, "OSAttr");
> + if (cmp == 0) {
> + m->osattr.value = talloc_move(m, &value);
> + m->osattr.flags = flags;
> +
> + continue;
> + }
> + }
> +
> + ok = mscat_asn1_oid_equal(oid, CAT_MEMBERINFO_OBJID);
> + if (ok) {
> + char *name;
> + uint32_t id;
> +
> + rc = ctl_parse_member_info(ctl,
> + tmp_ctx,
> + &content,
> + &name,
> + &id);
> + if (rc != 0) {
> + goto done;
> + }
> +
> + m->info.guid = talloc_move(m, &name);
> + m->info.id = id;
> +
> + continue;
> + }
> +
> + ok = mscat_asn1_oid_equal(oid, SPC_INDIRECT_DATA_OBJID);
> + if (ok) {
> + rc = ctl_spc_indirect_data(ctl,
> + m,
> + &content,
> + &m->mac.type,
> + &m->mac.digest,
> + &m->mac.digest_size);
> + if (rc != 0) {
> + goto done;
> + }
> +
> + continue;
> + }
> + }
> +
> + rc = 0;
> +done:
> + talloc_free(tmp_ctx);
> + return rc;
> +}
> +
> +int mscat_ctl_get_member(struct mscat_ctl *ctl,
> + TALLOC_CTX *mem_ctx,
> + unsigned int idx,
> + struct mscat_ctl_member **pmember)
> +{
> + TALLOC_CTX *tmp_ctx;
> + struct mscat_ctl_member *m = NULL;
> + int rc = -1;
> +
> + tmp_ctx = talloc_new(mem_ctx);
> + if (tmp_ctx == NULL) {
> + return -1;
> + }
> +
> + m = talloc_zero(tmp_ctx, struct mscat_ctl_member);
> + if (m == NULL) {
> + rc = -1;
> + goto done;
> + }
> +
> + if (ctl->version == 1) {
> + m->checksum.type = MSCAT_CHECKSUM_STRING;
> + rc = ctl_get_member_checksum_string(ctl,
> + m,
> + idx,
> + &m->checksum.string,
> + &m->checksum.size);
> + } else if (ctl->version == 2) {
> + m->checksum.type = MSCAT_CHECKSUM_BLOB;
> + rc = ctl_get_member_checksum_blob(ctl,
> + m,
> + idx,
> + &m->checksum.blob,
> + &m->checksum.size);
> + }
> + if (rc != 0) {
> + goto done;
> + }
> +
> + rc = ctl_get_member_attributes(ctl,
> + mem_ctx,
> + idx,
> + m);
> + if (rc != 0) {
> + goto done;
> + }
> +
> + *pmember = talloc_move(mem_ctx, &m);
> +
> + rc = 0;
> +done:
> + talloc_free(tmp_ctx);
> + return rc;
> +}
> +
> +int mscat_ctl_get_member_count(struct mscat_ctl *ctl)
> +{
> + int count = 0;
> + int rc;
> +
> + rc = asn1_number_of_elements(ctl->tree_ctl,
> + "members",
> + &count);
> + if (rc != ASN1_SUCCESS) {
> + return -1;
> + }
> +
> + return count;
> +}
> +
> +int mscat_ctl_get_attribute(struct mscat_ctl *ctl,
> + TALLOC_CTX *mem_ctx,
> + unsigned int idx,
> + struct mscat_ctl_attribute **pattribute)
> +{
> + TALLOC_CTX *tmp_ctx;
> + const char *el1 = NULL;
> + const char *el2 = NULL;
> + const char *oid = NULL;
> + char *name = NULL;
> + uint32_t flags = 0;
> + char *value = NULL;
> + struct mscat_ctl_attribute *a = NULL;
> + DATA_BLOB encapsulated_data_blob = data_blob_null;
> + int rc;
> +
> + tmp_ctx = talloc_new(mem_ctx);
> + if (tmp_ctx == NULL) {
> + return -1;
> + }
> +
> + a = talloc_zero(tmp_ctx, struct mscat_ctl_attribute);
> + if (a == NULL) {
> + rc = -1;
> + goto done;
> + }
> +
> + el1 = talloc_asprintf(tmp_ctx,
> + "attributes.?%u.dataId",
> + idx);
> + if (el1 == NULL) {
> + rc = -1;
> + goto done;
> + }
> +
> + oid = mscat_asn1_get_oid(tmp_ctx,
> + ctl->tree_ctl,
> + el1);
> + if (oid == NULL) {
> + rc = -1;
> + goto done;
> + }
> +
> + el2 = talloc_asprintf(tmp_ctx,
> + "attributes.?%u.encapsulated_data",
> + idx);
> + if (el2 == NULL) {
> + rc = -1;
> + goto done;
> + }
> +
> + rc = mscat_asn1_read_value(tmp_ctx,
> + ctl->tree_ctl,
> + el2,
> + &encapsulated_data_blob);
> + if (rc != ASN1_SUCCESS) {
> + goto done;
> + }
> +
> + rc = ctl_parse_name_value(ctl,
> + tmp_ctx,
> + &encapsulated_data_blob,
> + &name,
> + &flags,
> + &value);
> + if (rc != 0) {
> + goto done;
> + }
> +
> + a->name = talloc_move(a, &name);
> + a->flags = flags;
> + a->value = talloc_move(a, &value);
> +
> + *pattribute = talloc_move(mem_ctx, &a);
> +
> + rc = 0;
> +done:
> + talloc_free(tmp_ctx);
> + return rc;
> +}
> +
> +int mscat_ctl_get_attribute_count(struct mscat_ctl *ctl)
> +{
> + int count = 0;
> + int rc;
> +
> + rc = asn1_number_of_elements(ctl->tree_ctl,
> + "attributes",
> + &count);
> + if (rc != ASN1_SUCCESS) {
> + return -1;
> + }
> +
> + return count;
> +}
> diff --git a/lib/mscat/mscat_pkcs7.c b/lib/mscat/mscat_pkcs7.c
> new file mode 100644
> index 00000000000..55944232205
> --- /dev/null
> +++ b/lib/mscat/mscat_pkcs7.c
> @@ -0,0 +1,284 @@
> +/*
> + * Copyright (c) 2016 Andreas Schneider <asn at samba.org>
> + *
> + * This program is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, either version 3 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <errno.h>
> +#include <stdint.h>
> +#include <string.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <unistd.h>
> +
> +#include <util/debug.h>
> +#include <util/data_blob.h>
> +
> +#include "mscat.h"
> +#include "mscat_private.h"
> +
> +#define PKCS7_CTL_OBJID "1.3.6.1.4.1.311.10.1"
> +
> +static int mscat_pkcs7_cleanup(struct mscat_pkcs7 *mp7)
> +{
> + if (mp7->c != NULL) {
> + gnutls_pkcs7_deinit(mp7->c);
> + }
> +
> + return 0;
> +}
> +
> +struct mscat_pkcs7 *mscat_pkcs7_init(TALLOC_CTX *mem_ctx)
> +{
> + struct mscat_pkcs7 *pkcs7;
> + int rc;
> +
> + pkcs7 = talloc_zero(mem_ctx, struct mscat_pkcs7);
> + if (pkcs7 == NULL) {
> + return NULL;
> + }
> + talloc_set_destructor(pkcs7, mscat_pkcs7_cleanup);
> +
> + rc = gnutls_pkcs7_init(&pkcs7->c);
> + if (rc != 0) {
> + talloc_free(pkcs7);
> + return NULL;
> + }
> +
> + return pkcs7;
> +}
> +
> +static int mscat_read_file(TALLOC_CTX *mem_ctx,
> + const char *filename,
> + DATA_BLOB *pblob)
> +{
> + struct stat sb = {0};
> + size_t alloc_size;
> + size_t count;
> + DATA_BLOB blob;
> + FILE *fp;
> + int rc;
> +
> + fp = fopen(filename, "r");
> + if (fp == NULL) {
> + return -1;
> + }
> +
> + rc = fstat(fileno(fp), &sb);
> + if (rc != 0) {
> + goto error;
> + }
> +
> + if (!S_ISREG(sb.st_mode)) {
> + errno = EINVAL;
> + goto error;
> + }
> + if (SIZE_MAX - 1 < (unsigned long)sb.st_size) {
> + errno = ENOMEM;
> + goto error;
> + }
> + alloc_size = sb.st_size + 1;
> +
> + blob = data_blob_talloc_zero(mem_ctx, alloc_size);
> + if (blob.data == NULL) {
> + goto error;
> + }
> +
> + count = fread(blob.data, 1, blob.length, fp);
> + if (count != blob.length) {
> + if (ferror(fp)) {
> + goto error;
> + }
> + }
> + blob.data[count] = '\0';
> + blob.length = count;
> + fclose(fp);
> +
> + *pblob = blob;
> +
> + return 0;
> +error:
> + data_blob_free(&blob);
> + fclose(fp);
> + return rc;
> +}
> +
> +int mscat_pkcs7_import_catfile(struct mscat_pkcs7 *mp7,
> + const char *catfile)
> +{
> + TALLOC_CTX *tmp_ctx;
> + gnutls_datum_t mscat_data = {
> + .size = 0,
> + };
> + DATA_BLOB blob;
> + int rc;
> +
> + tmp_ctx = talloc_new(mp7);
> + if (tmp_ctx == NULL) {
> + return -1;
> + }
> +
> + rc = mscat_read_file(tmp_ctx,
> + catfile,
> + &blob);
> + if (rc == -1) {
> + DBG_ERR("Failed to read catalog file '%s' - %s",
> + catfile,
> + strerror(errno));
> + goto done;
> + }
> +
> + mscat_data.data = blob.data;
> + mscat_data.size = blob.length;
> +
> + rc = gnutls_pkcs7_import(mp7->c,
> + &mscat_data,
> + GNUTLS_X509_FMT_DER);
> + if (rc < 0) {
> + DBG_ERR("Failed to import PKCS7 from '%s' - %s",
> + catfile,
> + gnutls_strerror(rc));
> + goto done;
> + }
> +
> + rc = 0;
> +done:
> + talloc_free(tmp_ctx);
> + return rc;
> +}
> +
> +int mscat_pkcs7_verify(struct mscat_pkcs7 *mp7,
> + const char *ca_file)
> +{
> + TALLOC_CTX *tmp_ctx = NULL;
> + gnutls_x509_trust_list_t tl = NULL;
> + gnutls_datum_t ca_data;
> + DATA_BLOB blob;
> + uint32_t flags = 0;
> + const char *oid;
> + int count;
> + int cmp;
> + int rc;
> + int i;
> +
> + oid = gnutls_pkcs7_get_embedded_data_oid(mp7->c);
> + if (oid == NULL) {
> + DBG_ERR("Failed to get oid - %s",
> + gnutls_strerror(errno));
> + return -1;
> + }
> +
> + cmp = strcmp(oid, PKCS7_CTL_OBJID);
> + if (cmp != 0) {
> + DBG_ERR("Invalid oid in catalog file! oid: %s, expected: %s",
> + oid,
> + PKCS7_CTL_OBJID);
> + return -1;
> + }
> +
> + tmp_ctx = talloc_new(mp7);
> + if (tmp_ctx == NULL) {
> + return -1;
> + }
> +
> + rc = gnutls_x509_trust_list_init(&tl,
> + 0); /* default size */
> + if (rc != 0) {
> + DBG_ERR("Failed to create trust list - %s",
> + gnutls_strerror(rc));
> + goto done;
> + }
> +
> +
> + /* Load the system trust list */
> + rc = gnutls_x509_trust_list_add_system_trust(tl, 0, 0);
> + if (rc < 0) {
> + DBG_ERR("Failed to add system trust list - %s",
> + gnutls_strerror(rc));
> + goto done;
> + }
> + DBG_INFO("Loaded %d CAs", rc);
> +
> + if (ca_file != NULL) {
> + rc = mscat_read_file(tmp_ctx,
> + ca_file,
> + &blob);
> + if (rc != 0) {
> + DBG_ERR("Failed to read CA file '%s' - %s",
> + ca_file,
> + strerror(errno));
> + goto done;
> + }
> +
> + ca_data.data = blob.data;
> + ca_data.size = blob.length;
> +
> + rc = gnutls_x509_trust_list_add_trust_mem(tl,
> + &ca_data,
> + NULL, /* crls */
> + GNUTLS_X509_FMT_DER,
> + 0, /* tl_flags */
> + 0); /* tl_vflags */
> + if (rc < 0) {
> + DBG_ERR("Failed to add '%s' to trust list - %s (%d)",
> + ca_file,
> + gnutls_strerror(rc),
> + rc);
> + goto done;
> + }
> + DBG_INFO("Loaded %d additional CAs", rc);
> + }
> +
> + /*
> + * Drivers often exist for quite some time, so it is possible that one
> + * of the certificates in the trust list expired.
> + * This is not a big deal, but we need to disable the time checks
> + * or the verification will fail.
> + */
> + flags = GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS|
> + GNUTLS_VERIFY_DISABLE_TIME_CHECKS;
> +
> +#if GNUTLS_VERSION_NUMBER >= 0x030600
> + /* The "Microsoft Root Authority" certificate uses SHA1 */
> + flags |= GNUTLS_VERIFY_ALLOW_SIGN_WITH_SHA1;
> +#endif
> +
> + count = gnutls_pkcs7_get_signature_count(mp7->c);
> + if (count == 0) {
> + DBG_ERR("Failed to verify catalog file, no signatures found");
> + goto done;
> + }
> +
> + for (i = 0; i < count; i++) {
> + rc = gnutls_pkcs7_verify(mp7->c,
> + tl,
> + NULL, /* vdata */
> + 0, /* vdata_size */
> + i, /* index */
> + NULL, /* data */
> + flags); /* flags */
> + if (rc < 0) {
> + DBG_ERR("Failed to verify catalog file - %s (%d)",
> + gnutls_strerror(rc),
> + rc);
> + goto done;
> + }
> + }
> +
> + rc = 0;
> +done:
> + gnutls_x509_trust_list_deinit(tl, 1);
> + talloc_free(tmp_ctx);
> + return rc;
> +}
> diff --git a/lib/mscat/mscat_private.h b/lib/mscat/mscat_private.h
> new file mode 100644
> index 00000000000..d79b364ceb0
> --- /dev/null
> +++ b/lib/mscat/mscat_private.h
> @@ -0,0 +1,27 @@
> +/*
> + * Copyright (c) 2016 Andreas Schneider <asn at samba.org>
> + *
> + * This program is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, either version 3 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef _MSCAT_PRIVATE_H
> +#define _MSCAT_PRIVATE_H
> +
> +#include <gnutls/pkcs7.h>
> +
> +struct mscat_pkcs7 {
> + gnutls_pkcs7_t c;
> +};
> +
> +#endif /* _MSCAT_PRIVATE_H */
> diff --git a/lib/mscat/wscript b/lib/mscat/wscript
> new file mode 100644
> index 00000000000..951de7fe42a
> --- /dev/null
> +++ b/lib/mscat/wscript
> @@ -0,0 +1,42 @@
> +#!/usr/bin/env python
> +
> +import os
> +import Logs
> +import sys
> +
> +def configure(conf):
> + pkg_name = 'libtasn1'
> + pkg_minversion = '3.8'
> +
> + if conf.CHECK_BUNDLED_SYSTEM_PKG(pkg_name, minversion=pkg_minversion):
> + if not conf.find_program('asn1Parser', var='ASN1PARSER'):
> + Logs.error('ERROR: You need to make sure asn1Parser is available')
> + sys.exit(1)
> +
> + conf.CHECK_FUNCS_IN('gnutls_pkcs7_get_embedded_data_oid', 'gnutls')
> +
> +def build(bld):
> + if bld.CONFIG_SET('HAVE_LIBTASN1') and bld.CONFIG_SET('HAVE_GNUTLS_PKCS7_GET_EMBEDDED_DATA_OID'):
> + bld.SAMBA_GENERATOR('MSCAT_PARSER',
> + source='mscat.asn',
> + target='mscat_asn1_tab.c',
> + rule='${ASN1PARSER} --output ${TGT} ${SRC}',
> + group='build_source')
> +
> + bld.SAMBA_LIBRARY('mscat',
> + source='''
> + mscat_asn1_tab.c
> + mscat_ctl.c
> + mscat_pkcs7.c
> + ''',
> + deps='''
> + talloc
> + gnutls
> + libtasn1
> + samba-util
> + ''',
> + private_library=True)
> +
> + bld.SAMBA_BINARY('dumpmscat',
> + source='dumpmscat.c',
> + deps='mscat')
> diff --git a/wscript b/wscript
> index f11c49dde67..f98d731e537 100644
> --- a/wscript
> +++ b/wscript
> @@ -279,6 +279,7 @@ def configure(conf):
> if conf.env.with_ctdb:
> conf.RECURSE('ctdb')
> conf.RECURSE('lib/socket')
> + conf.RECURSE('lib/mscat')
> conf.RECURSE('packaging')
>
> conf.SAMBA_CHECK_UNDEFINED_SYMBOL_FLAGS()
> diff --git a/wscript_build b/wscript_build
> index 54548769b19..51fe553a8c1 100644
> --- a/wscript_build
> +++ b/wscript_build
> @@ -117,6 +117,7 @@ bld.RECURSE('libcli/echo')
> bld.RECURSE('libcli/dns')
> bld.RECURSE('libcli/samsync')
> bld.RECURSE('libcli/registry')
> +bld.RECURSE('lib/mscat')
> bld.RECURSE('source4/lib/policy')
> bld.RECURSE('libcli/named_pipe_auth')
> if bld.CONFIG_GET('ENABLE_SELFTEST'):
> --
> 2.18.0
>
More information about the samba-technical
mailing list