2 * Copyright (c) 2016 Andreas Schneider <asn@samba.org>
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include <util/debug.h>
23 #include <util/byteorder.h>
24 #include <util/data_blob.h>
28 #include "mscat_private.h"
30 #define ASN1_NULL_DATA "\x05\x00"
31 #define ASN1_NULL_DATA_SIZE 2
33 #define HASH_SHA1_OBJID "1.3.14.3.2.26"
34 #define HASH_SHA256_OBJID "2.16.840.1.101.3.4.2.1"
35 #define HASH_SHA512_OBJID "2.16.840.1.101.3.4.2.3"
37 #define SPC_INDIRECT_DATA_OBJID "1.3.6.1.4.1.311.2.1.4"
38 #define SPC_PE_IMAGE_DATA_OBJID "1.3.6.1.4.1.311.2.1.15"
40 #define CATALOG_LIST_OBJOID "1.3.6.1.4.1.311.12.1.1"
41 #define CATALOG_LIST_MEMBER_OBJOID "1.3.6.1.4.1.311.12.1.2"
42 #define CATALOG_LIST_MEMBER_V2_OBJOID "1.3.6.1.4.1.311.12.1.3"
44 #define CAT_NAME_VALUE_OBJID "1.3.6.1.4.1.311.12.2.1"
45 #define CAT_MEMBERINFO_OBJID "1.3.6.1.4.1.311.12.2.2"
47 extern const asn1_static_node mscat_asn1_tab
[];
53 gnutls_datum_t raw_ctl
;
56 static char *mscat_asn1_get_oid(TALLOC_CTX
*mem_ctx
,
60 char oid_str
[32] = {0};
61 int oid_len
= sizeof(oid_str
);
64 rc
= asn1_read_value(root
,
68 if (rc
!= ASN1_SUCCESS
) {
69 DBG_ERR("Failed to read value '%s': %s\n",
75 return talloc_strndup(mem_ctx
, oid_str
, oid_len
);
78 static bool mscat_asn1_oid_equal(const char *o1
, const char *o2
)
90 static int mscat_asn1_read_value(TALLOC_CTX
*mem_ctx
,
95 DATA_BLOB tmp
= data_blob_null
;
96 unsigned int etype
= ASN1_ETYPE_INVALID
;
101 rc
= asn1_read_value_type(root
, name
, NULL
, &tmp_len
, &etype
);
102 if (rc
!= ASN1_SUCCESS
) {
107 if (etype
== ASN1_ETYPE_BIT_STRING
) {
115 *blob
= data_blob_null
;
122 tmp
= data_blob_talloc_zero(mem_ctx
, len
+ 1);
123 if (tmp
.data
== NULL
) {
127 rc
= asn1_read_value(root
,
131 if (rc
!= ASN1_SUCCESS
) {
132 data_blob_free(&tmp
);
137 if (etype
== ASN1_ETYPE_BIT_STRING
) {
150 static int mscat_ctl_cleanup(struct mscat_ctl
*ctl
)
152 if (ctl
->asn1_desc
!= NULL
) {
153 asn1_delete_structure(&ctl
->asn1_desc
);
159 struct mscat_ctl
*mscat_ctl_init(TALLOC_CTX
*mem_ctx
)
161 char error_string
[ASN1_MAX_ERROR_DESCRIPTION_SIZE
] = {0};
162 struct mscat_ctl
*cat_ctl
= NULL
;
165 cat_ctl
= talloc_zero(mem_ctx
, struct mscat_ctl
);
166 if (cat_ctl
== NULL
) {
169 talloc_set_destructor(cat_ctl
, mscat_ctl_cleanup
);
171 cat_ctl
->asn1_desc
= NULL
;
172 cat_ctl
->tree_ctl
= NULL
;
174 rc
= asn1_array2tree(mscat_asn1_tab
,
177 if (rc
!= ASN1_SUCCESS
) {
178 talloc_free(cat_ctl
);
179 DBG_ERR("Failed to create parser tree: %s - %s\n",
188 int mscat_ctl_import(struct mscat_ctl
*ctl
,
189 struct mscat_pkcs7
*pkcs7
)
191 char error_string
[ASN1_MAX_ERROR_DESCRIPTION_SIZE
] = {0};
192 TALLOC_CTX
*tmp_ctx
= NULL
;
197 rc
= gnutls_pkcs7_get_embedded_data(pkcs7
->c
,
198 GNUTLS_PKCS7_EDATA_GET_RAW
,
200 if (rc
!= GNUTLS_E_SUCCESS
) {
201 DBG_ERR("Failed to get embedded data from pkcs7: %s\n",
202 gnutls_strerror(rc
));
206 rc
= asn1_create_element(ctl
->asn1_desc
,
207 "CATALOG.CertTrustList",
209 if (rc
!= ASN1_SUCCESS
) {
210 DBG_ERR("Failed to create CertTrustList ASN.1 element - %s\n",
215 rc
= asn1_der_decoding(&ctl
->tree_ctl
,
219 if (rc
!= ASN1_SUCCESS
) {
220 DBG_ERR("Failed to parse ASN.1 CertTrustList: %s - %s\n",
226 tmp_ctx
= talloc_new(ctl
);
227 if (tmp_ctx
== NULL
) {
231 oid
= mscat_asn1_get_oid(tmp_ctx
,
233 "catalogListId.oid");
239 ok
= mscat_asn1_oid_equal(oid
, CATALOG_LIST_OBJOID
);
241 DBG_ERR("Invalid oid (%s), expected CATALOG_LIST_OBJOID\n",
248 oid
= mscat_asn1_get_oid(tmp_ctx
,
250 "catalogListMemberId.oid");
256 ok
= mscat_asn1_oid_equal(oid
, CATALOG_LIST_MEMBER_V2_OBJOID
);
260 ok
= mscat_asn1_oid_equal(oid
, CATALOG_LIST_MEMBER_OBJOID
);
264 DBG_ERR("Invalid oid (%s), expected "
265 "CATALOG_LIST_MEMBER_OBJOID\n",
274 talloc_free(tmp_ctx
);
278 static int ctl_get_member_checksum_string(struct mscat_ctl
*ctl
,
281 const char **pchecksum
,
282 size_t *pchecksum_size
)
285 DATA_BLOB chksum_ucs2
= data_blob_null
;
286 size_t converted_size
= 0;
287 char *checksum
= NULL
;
288 char *element
= NULL
;
292 tmp_ctx
= talloc_new(mem_ctx
);
293 if (tmp_ctx
== NULL
) {
297 element
= talloc_asprintf(tmp_ctx
,
298 "members.?%u.checksum",
300 if (element
== NULL
) {
304 rc
= mscat_asn1_read_value(tmp_ctx
,
308 talloc_free(element
);
313 ok
= convert_string_talloc(mem_ctx
,
325 *pchecksum_size
= strlen(checksum
) + 1;
326 *pchecksum
= talloc_move(mem_ctx
, &checksum
);
330 talloc_free(tmp_ctx
);
334 static int ctl_get_member_checksum_blob(struct mscat_ctl
*ctl
,
338 size_t *pchecksum_size
)
341 DATA_BLOB chksum
= data_blob_null
;
342 char *element
= NULL
;
345 tmp_ctx
= talloc_new(mem_ctx
);
346 if (tmp_ctx
== NULL
) {
350 element
= talloc_asprintf(tmp_ctx
,
351 "members.?%u.checksum",
353 if (element
== NULL
) {
357 rc
= mscat_asn1_read_value(tmp_ctx
,
361 talloc_free(element
);
366 *pchecksum
= talloc_move(mem_ctx
, &chksum
.data
);
367 *pchecksum_size
= chksum
.length
;
371 talloc_free(tmp_ctx
);
375 static int ctl_parse_name_value(struct mscat_ctl
*ctl
,
382 char error_string
[ASN1_MAX_ERROR_DESCRIPTION_SIZE
] = {0};
383 asn1_node name_value
= NULL
;
385 DATA_BLOB name_blob
= data_blob_null
;
386 DATA_BLOB flags_blob
= data_blob_null
;
387 DATA_BLOB value_blob
= data_blob_null
;
388 size_t converted_size
= 0;
392 tmp_ctx
= talloc_new(mem_ctx
);
393 if (tmp_ctx
== NULL
) {
397 rc
= asn1_create_element(ctl
->asn1_desc
,
398 "CATALOG.CatalogNameValue",
400 if (rc
!= ASN1_SUCCESS
) {
401 DBG_ERR("Failed to create element for "
402 "CATALOG.CatalogNameValue: %s\n",
407 rc
= asn1_der_decoding(&name_value
,
411 if (rc
!= ASN1_SUCCESS
) {
412 DBG_ERR("Failed to decode CATALOG.CatalogNameValue: %s - %s\n",
418 rc
= mscat_asn1_read_value(mem_ctx
,
422 if (rc
!= ASN1_SUCCESS
) {
423 DBG_ERR("Failed to read 'name': %s\n",
428 rc
= mscat_asn1_read_value(mem_ctx
,
432 if (rc
!= ASN1_SUCCESS
) {
433 DBG_ERR("Failed to read 'flags': %s\n",
438 rc
= mscat_asn1_read_value(mem_ctx
,
442 if (rc
!= ASN1_SUCCESS
) {
443 DBG_ERR("Failed to read 'value': %s\n",
448 ok
= convert_string_talloc(mem_ctx
,
460 *pflags
= RIVAL(flags_blob
.data
, 0);
462 ok
= convert_string_talloc(mem_ctx
,
476 talloc_free(tmp_ctx
);
480 static int ctl_parse_member_info(struct mscat_ctl
*ctl
,
486 char error_string
[ASN1_MAX_ERROR_DESCRIPTION_SIZE
] = {0};
487 asn1_node member_info
= NULL
;
489 DATA_BLOB name_blob
= data_blob_null
;
490 DATA_BLOB id_blob
= data_blob_null
;
491 size_t converted_size
= 0;
495 tmp_ctx
= talloc_new(mem_ctx
);
496 if (tmp_ctx
== NULL
) {
500 rc
= asn1_create_element(ctl
->asn1_desc
,
501 "CATALOG.CatalogMemberInfo",
503 if (rc
!= ASN1_SUCCESS
) {
504 DBG_ERR("Failed to create element for "
505 "CATALOG.CatalogMemberInfo: %s\n",
510 rc
= asn1_der_decoding(&member_info
,
514 if (rc
!= ASN1_SUCCESS
) {
515 DBG_ERR("Failed to decode CATALOG.CatalogMemberInfo: %s - %s\n",
521 rc
= mscat_asn1_read_value(mem_ctx
,
525 if (rc
!= ASN1_SUCCESS
) {
526 DBG_ERR("Failed to read 'name': %s\n",
531 rc
= mscat_asn1_read_value(mem_ctx
,
535 if (rc
!= ASN1_SUCCESS
) {
536 DBG_ERR("Failed to read 'id': %s\n",
541 ok
= convert_string_talloc(mem_ctx
,
553 *pid
= RSVAL(id_blob
.data
, 0);
557 talloc_free(tmp_ctx
);
562 static int ctl_spc_pe_image_data(struct mscat_ctl
*ctl
,
567 char error_string
[ASN1_MAX_ERROR_DESCRIPTION_SIZE
] = {0};
568 asn1_node spc_pe_image_data
= NULL
;
569 DATA_BLOB flags_blob
= data_blob_null
;
570 DATA_BLOB choice_blob
= data_blob_null
;
576 tmp_ctx
= talloc_new(mem_ctx
);
577 if (tmp_ctx
== NULL
) {
581 rc
= asn1_create_element(ctl
->asn1_desc
,
582 "CATALOG.SpcPEImageData",
584 if (rc
!= ASN1_SUCCESS
) {
585 DBG_ERR("Failed to create element for "
586 "CATALOG.SpcPEImageData: %s\n",
591 rc
= asn1_der_decoding(&spc_pe_image_data
,
595 if (rc
!= ASN1_SUCCESS
) {
596 DBG_ERR("Failed to decode CATALOG.SpcPEImageData: %s - %s\n",
602 rc
= mscat_asn1_read_value(tmp_ctx
,
606 if (rc
== ASN1_SUCCESS
) {
607 uint32_t flags
= RIVAL(flags_blob
.data
, 0);
609 DBG_ERR(">>> SPC_PE_IMAGE_DATA FLAGS=0x%08x\n",
612 DBG_ERR("Failed to parse 'flags' in CATALOG.SpcPEImageData - %s\n",
617 rc
= mscat_asn1_read_value(tmp_ctx
,
621 if (rc
!= ASN1_SUCCESS
) {
622 DBG_ERR("Failed to parse 'link' in CATALOG.SpcPEImageData - %s\n",
627 cmp
= strncmp((char *)choice_blob
.data
, "url", choice_blob
.length
);
629 /* Never seen in a printer catalog file yet */
630 DBG_INFO("Please report a Samba bug and attach the catalog "
634 cmp
= strncmp((char *)choice_blob
.data
, "moniker", choice_blob
.length
);
636 /* Never seen in a printer catalog file yet */
637 DBG_INFO("Please report a Samba bug and attach the catalog "
641 cmp
= strncmp((char *)choice_blob
.data
, "file", choice_blob
.length
);
646 rc
= mscat_asn1_read_value(tmp_ctx
,
650 if (rc
!= ASN1_SUCCESS
) {
654 link
= talloc_asprintf(tmp_ctx
, "link.file.%s", (char *)choice_blob
.data
);
660 rc
= mscat_asn1_read_value(tmp_ctx
,
664 if (rc
!= ASN1_SUCCESS
) {
665 DBG_ERR("Failed to read '%s' - %s\n",
672 cmp
= strncmp((char *)choice_blob
.data
, "unicode", choice_blob
.length
);
674 size_t converted_size
= 0;
677 ok
= convert_string_talloc(tmp_ctx
,
690 cmp
= strncmp((char *)choice_blob
.data
, "ascii", choice_blob
.length
);
692 file
= talloc_strndup(tmp_ctx
,
693 (char *)file_blob
.data
,
703 *pfile
= talloc_move(mem_ctx
, &file
);
708 talloc_free(tmp_ctx
);
712 static int ctl_spc_indirect_data(struct mscat_ctl
*ctl
,
715 enum mscat_mac_algorithm
*pmac_algorithm
,
717 size_t *pdigest_size
)
719 char error_string
[ASN1_MAX_ERROR_DESCRIPTION_SIZE
] = {0};
720 asn1_node spc_indirect_data
= NULL
;
722 enum mscat_mac_algorithm mac_algorithm
= MSCAT_MAC_UNKNOWN
;
723 const char *oid
= NULL
;
724 DATA_BLOB data_value_blob
= data_blob_null
;
725 DATA_BLOB digest_parameters_blob
= data_blob_null
;
726 DATA_BLOB digest_blob
= data_blob_null
;
730 tmp_ctx
= talloc_new(mem_ctx
);
731 if (tmp_ctx
== NULL
) {
735 rc
= asn1_create_element(ctl
->asn1_desc
,
736 "CATALOG.SpcIndirectData",
738 if (rc
!= ASN1_SUCCESS
) {
739 DBG_ERR("Failed to create element for "
740 "CATALOG.SpcIndirectData: %s\n",
745 rc
= asn1_der_decoding(&spc_indirect_data
,
749 if (rc
!= ASN1_SUCCESS
) {
750 DBG_ERR("Failed to decode CATALOG.SpcIndirectData: %s - %s\n",
756 oid
= mscat_asn1_get_oid(tmp_ctx
,
763 rc
= mscat_asn1_read_value(tmp_ctx
,
767 if (rc
!= ASN1_SUCCESS
) {
768 DBG_ERR("Failed to find data.value in SpcIndirectData: %s\n",
773 ok
= mscat_asn1_oid_equal(oid
, SPC_PE_IMAGE_DATA_OBJID
);
777 rc
= ctl_spc_pe_image_data(ctl
,
785 /* Just returns <<<Obsolete>>> as file */
786 DBG_NOTICE(">>> LINK: %s\n",
790 oid
= mscat_asn1_get_oid(tmp_ctx
,
792 "messageDigest.digestAlgorithm.algorithm");
797 rc
= mscat_asn1_read_value(tmp_ctx
,
799 "messageDigest.digestAlgorithm.parameters",
800 &digest_parameters_blob
);
801 if (rc
== ASN1_SUCCESS
) {
802 /* Make sure we don't have garbage */
805 if (digest_parameters_blob
.length
!= ASN1_NULL_DATA_SIZE
) {
809 cmp
= memcmp(digest_parameters_blob
.data
,
811 digest_parameters_blob
.length
);
816 } else if (rc
!= ASN1_ELEMENT_NOT_FOUND
) {
817 DBG_ERR("Failed to read 'messageDigest.digestAlgorithm.parameters': %s\n",
822 ok
= mscat_asn1_oid_equal(oid
, HASH_SHA1_OBJID
);
824 mac_algorithm
= MSCAT_MAC_SHA1
;
827 ok
= mscat_asn1_oid_equal(oid
, HASH_SHA256_OBJID
);
829 mac_algorithm
= MSCAT_MAC_SHA256
;
832 if (mac_algorithm
!= MSCAT_MAC_UNKNOWN
&&
833 mac_algorithm
!= MSCAT_MAC_NULL
) {
834 rc
= mscat_asn1_read_value(tmp_ctx
,
836 "messageDigest.digest",
838 if (rc
!= ASN1_SUCCESS
) {
839 DBG_ERR("Failed to find messageDigest.digest in "
840 "SpcIndirectData: %s\n",
846 *pmac_algorithm
= mac_algorithm
;
847 *pdigest
= talloc_move(mem_ctx
, &digest_blob
.data
);
848 *pdigest_size
= digest_blob
.length
;
852 talloc_free(tmp_ctx
);
856 static int ctl_get_member_attributes(struct mscat_ctl
*ctl
,
859 struct mscat_ctl_member
*m
)
867 tmp_ctx
= talloc_new(mem_ctx
);
868 if (tmp_ctx
== NULL
) {
872 el1
= talloc_asprintf(tmp_ctx
,
873 "members.?%u.attributes",
879 rc
= asn1_number_of_elements(ctl
->tree_ctl
,
882 if (rc
!= ASN1_SUCCESS
) {
886 for (i
= 0; i
< count
; i
++) {
887 int content_start
= 0;
895 el2
= talloc_asprintf(tmp_ctx
,
896 "%s.?%d.contentType",
904 oid
= mscat_asn1_get_oid(tmp_ctx
,
913 /* FIXME Looks like this is always 1 */
914 el2
= talloc_asprintf(tmp_ctx
,
923 DBG_DEBUG("Decode element (startEnd) %s\n",
926 rc
= asn1_der_decoding_startEnd(ctl
->tree_ctl
,
932 if (rc
!= ASN1_SUCCESS
) {
935 if (content_start
< content_end
) {
938 content_len
= content_end
- content_start
+ 1;
940 DBG_DEBUG("Content data_blob length: %zu\n",
943 content
= data_blob_talloc_zero(tmp_ctx
, content_len
);
944 if (content
.data
== NULL
) {
949 &ctl
->raw_ctl
.data
[content_start
],
952 ok
= mscat_asn1_oid_equal(oid
, CAT_NAME_VALUE_OBJID
);
959 rc
= ctl_parse_name_value(ctl
,
969 DBG_DEBUG("Parsed NameValue: name=%s, flags=%u, value=%s\n",
974 cmp
= strcmp(name
, "File");
976 m
->file
.name
= talloc_move(m
, &value
);
977 m
->file
.flags
= flags
;
982 cmp
= strcmp(name
, "OSAttr");
984 m
->osattr
.value
= talloc_move(m
, &value
);
985 m
->osattr
.flags
= flags
;
991 ok
= mscat_asn1_oid_equal(oid
, CAT_MEMBERINFO_OBJID
);
996 rc
= ctl_parse_member_info(ctl
,
1005 m
->info
.guid
= talloc_move(m
, &name
);
1011 ok
= mscat_asn1_oid_equal(oid
, SPC_INDIRECT_DATA_OBJID
);
1013 rc
= ctl_spc_indirect_data(ctl
,
1018 &m
->mac
.digest_size
);
1029 talloc_free(tmp_ctx
);
1033 int mscat_ctl_get_member(struct mscat_ctl
*ctl
,
1034 TALLOC_CTX
*mem_ctx
,
1036 struct mscat_ctl_member
**pmember
)
1038 TALLOC_CTX
*tmp_ctx
;
1039 struct mscat_ctl_member
*m
= NULL
;
1042 tmp_ctx
= talloc_new(mem_ctx
);
1043 if (tmp_ctx
== NULL
) {
1047 m
= talloc_zero(tmp_ctx
, struct mscat_ctl_member
);
1053 if (ctl
->version
== 1) {
1054 m
->checksum
.type
= MSCAT_CHECKSUM_STRING
;
1055 rc
= ctl_get_member_checksum_string(ctl
,
1058 &m
->checksum
.string
,
1060 } else if (ctl
->version
== 2) {
1061 m
->checksum
.type
= MSCAT_CHECKSUM_BLOB
;
1062 rc
= ctl_get_member_checksum_blob(ctl
,
1072 rc
= ctl_get_member_attributes(ctl
,
1080 *pmember
= talloc_move(mem_ctx
, &m
);
1084 talloc_free(tmp_ctx
);
1088 int mscat_ctl_get_member_count(struct mscat_ctl
*ctl
)
1093 rc
= asn1_number_of_elements(ctl
->tree_ctl
,
1096 if (rc
!= ASN1_SUCCESS
) {
1103 int mscat_ctl_get_attribute(struct mscat_ctl
*ctl
,
1104 TALLOC_CTX
*mem_ctx
,
1106 struct mscat_ctl_attribute
**pattribute
)
1108 TALLOC_CTX
*tmp_ctx
;
1109 const char *el1
= NULL
;
1110 const char *el2
= NULL
;
1111 const char *oid
= NULL
;
1115 struct mscat_ctl_attribute
*a
= NULL
;
1116 DATA_BLOB encapsulated_data_blob
= data_blob_null
;
1119 tmp_ctx
= talloc_new(mem_ctx
);
1120 if (tmp_ctx
== NULL
) {
1124 a
= talloc_zero(tmp_ctx
, struct mscat_ctl_attribute
);
1130 el1
= talloc_asprintf(tmp_ctx
,
1131 "attributes.?%u.dataId",
1138 oid
= mscat_asn1_get_oid(tmp_ctx
,
1146 el2
= talloc_asprintf(tmp_ctx
,
1147 "attributes.?%u.encapsulated_data",
1154 rc
= mscat_asn1_read_value(tmp_ctx
,
1157 &encapsulated_data_blob
);
1158 if (rc
!= ASN1_SUCCESS
) {
1162 rc
= ctl_parse_name_value(ctl
,
1164 &encapsulated_data_blob
,
1172 a
->name
= talloc_move(a
, &name
);
1174 a
->value
= talloc_move(a
, &value
);
1176 *pattribute
= talloc_move(mem_ctx
, &a
);
1180 talloc_free(tmp_ctx
);
1184 int mscat_ctl_get_attribute_count(struct mscat_ctl
*ctl
)
1189 rc
= asn1_number_of_elements(ctl
->tree_ctl
,
1192 if (rc
!= ASN1_SUCCESS
) {