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
;
100 rc
= asn1_read_value_type(root
, name
, NULL
, &len
, &etype
);
101 if (rc
!= ASN1_SUCCESS
) {
105 if (etype
== ASN1_ETYPE_BIT_STRING
) {
113 *blob
= data_blob_null
;
120 tmp
= data_blob_talloc_zero(mem_ctx
, len
+ 1);
121 if (tmp
.data
== NULL
) {
125 rc
= asn1_read_value(root
,
129 if (rc
!= ASN1_SUCCESS
) {
130 data_blob_free(&tmp
);
134 if (etype
== ASN1_ETYPE_BIT_STRING
) {
147 static int mscat_ctl_cleanup(struct mscat_ctl
*ctl
)
149 if (ctl
->asn1_desc
!= ASN1_TYPE_EMPTY
) {
150 asn1_delete_structure(&ctl
->asn1_desc
);
156 struct mscat_ctl
*mscat_ctl_init(TALLOC_CTX
*mem_ctx
)
158 char error_string
[ASN1_MAX_ERROR_DESCRIPTION_SIZE
] = {0};
159 struct mscat_ctl
*cat_ctl
= NULL
;
162 cat_ctl
= talloc_zero(mem_ctx
, struct mscat_ctl
);
163 if (cat_ctl
== NULL
) {
166 talloc_set_destructor(cat_ctl
, mscat_ctl_cleanup
);
168 cat_ctl
->asn1_desc
= ASN1_TYPE_EMPTY
;
169 cat_ctl
->tree_ctl
= ASN1_TYPE_EMPTY
;
171 rc
= asn1_array2tree(mscat_asn1_tab
,
174 if (rc
!= ASN1_SUCCESS
) {
175 talloc_free(cat_ctl
);
176 DBG_ERR("Failed to create parser tree: %s - %s\n",
185 int mscat_ctl_import(struct mscat_ctl
*ctl
,
186 struct mscat_pkcs7
*pkcs7
)
188 char error_string
[ASN1_MAX_ERROR_DESCRIPTION_SIZE
] = {0};
189 TALLOC_CTX
*tmp_ctx
= NULL
;
194 rc
= gnutls_pkcs7_get_embedded_data(pkcs7
->c
,
195 GNUTLS_PKCS7_EDATA_GET_RAW
,
197 if (rc
!= GNUTLS_E_SUCCESS
) {
198 DBG_ERR("Failed to get embedded data from pkcs7: %s\n",
199 gnutls_strerror(rc
));
203 rc
= asn1_create_element(ctl
->asn1_desc
,
204 "CATALOG.CertTrustList",
206 if (rc
!= ASN1_SUCCESS
) {
207 DBG_ERR("Failed to create CertTrustList ASN.1 element - %s\n",
212 rc
= asn1_der_decoding(&ctl
->tree_ctl
,
216 if (rc
!= ASN1_SUCCESS
) {
217 DBG_ERR("Failed to parse ASN.1 CertTrustList: %s - %s\n",
223 tmp_ctx
= talloc_new(ctl
);
224 if (tmp_ctx
== NULL
) {
228 oid
= mscat_asn1_get_oid(tmp_ctx
,
230 "catalogListId.oid");
236 ok
= mscat_asn1_oid_equal(oid
, CATALOG_LIST_OBJOID
);
238 DBG_ERR("Invalid oid (%s), expected CATALOG_LIST_OBJOID",
245 oid
= mscat_asn1_get_oid(tmp_ctx
,
247 "catalogListMemberId.oid");
253 ok
= mscat_asn1_oid_equal(oid
, CATALOG_LIST_MEMBER_V2_OBJOID
);
257 ok
= mscat_asn1_oid_equal(oid
, CATALOG_LIST_MEMBER_OBJOID
);
261 DBG_ERR("Invalid oid (%s), expected "
262 "CATALOG_LIST_MEMBER_OBJOID",
271 talloc_free(tmp_ctx
);
275 static int ctl_get_member_checksum_string(struct mscat_ctl
*ctl
,
278 const char **pchecksum
,
279 size_t *pchecksum_size
)
282 DATA_BLOB chksum_ucs2
= data_blob_null
;
283 size_t converted_size
= 0;
284 char *checksum
= NULL
;
285 char *element
= NULL
;
289 tmp_ctx
= talloc_new(mem_ctx
);
290 if (tmp_ctx
== NULL
) {
294 element
= talloc_asprintf(tmp_ctx
,
295 "members.?%u.checksum",
297 if (element
== NULL
) {
301 rc
= mscat_asn1_read_value(tmp_ctx
,
305 talloc_free(element
);
310 ok
= convert_string_talloc(mem_ctx
,
322 *pchecksum_size
= strlen(checksum
) + 1;
323 *pchecksum
= talloc_move(mem_ctx
, &checksum
);
327 talloc_free(tmp_ctx
);
331 static int ctl_get_member_checksum_blob(struct mscat_ctl
*ctl
,
335 size_t *pchecksum_size
)
338 DATA_BLOB chksum
= data_blob_null
;
339 char *element
= NULL
;
342 tmp_ctx
= talloc_new(mem_ctx
);
343 if (tmp_ctx
== NULL
) {
347 element
= talloc_asprintf(tmp_ctx
,
348 "members.?%u.checksum",
350 if (element
== NULL
) {
354 rc
= mscat_asn1_read_value(tmp_ctx
,
358 talloc_free(element
);
363 *pchecksum
= talloc_move(mem_ctx
, &chksum
.data
);
364 *pchecksum_size
= chksum
.length
;
368 talloc_free(tmp_ctx
);
372 static int ctl_parse_name_value(struct mscat_ctl
*ctl
,
379 char error_string
[ASN1_MAX_ERROR_DESCRIPTION_SIZE
] = {0};
380 ASN1_TYPE name_value
= ASN1_TYPE_EMPTY
;
382 DATA_BLOB name_blob
= data_blob_null
;
383 DATA_BLOB flags_blob
= data_blob_null
;
384 DATA_BLOB value_blob
= data_blob_null
;
385 size_t converted_size
= 0;
389 tmp_ctx
= talloc_new(mem_ctx
);
390 if (tmp_ctx
== NULL
) {
394 rc
= asn1_create_element(ctl
->asn1_desc
,
395 "CATALOG.CatalogNameValue",
397 if (rc
!= ASN1_SUCCESS
) {
398 DBG_ERR("Failed to create element for "
399 "CATALOG.CatalogNameValue: %s\n",
404 rc
= asn1_der_decoding(&name_value
,
408 if (rc
!= ASN1_SUCCESS
) {
409 DBG_ERR("Failed to decode CATALOG.CatalogNameValue: %s - %s",
415 rc
= mscat_asn1_read_value(mem_ctx
,
419 if (rc
!= ASN1_SUCCESS
) {
420 DBG_ERR("Failed to read 'name': %s\n",
425 rc
= mscat_asn1_read_value(mem_ctx
,
429 if (rc
!= ASN1_SUCCESS
) {
430 DBG_ERR("Failed to read 'flags': %s\n",
435 rc
= mscat_asn1_read_value(mem_ctx
,
439 if (rc
!= ASN1_SUCCESS
) {
440 DBG_ERR("Failed to read 'value': %s\n",
445 ok
= convert_string_talloc(mem_ctx
,
457 *pflags
= RIVAL(flags_blob
.data
, 0);
459 ok
= convert_string_talloc(mem_ctx
,
473 talloc_free(tmp_ctx
);
477 static int ctl_parse_member_info(struct mscat_ctl
*ctl
,
483 char error_string
[ASN1_MAX_ERROR_DESCRIPTION_SIZE
] = {0};
484 ASN1_TYPE member_info
= ASN1_TYPE_EMPTY
;
486 DATA_BLOB name_blob
= data_blob_null
;
487 DATA_BLOB id_blob
= data_blob_null
;
488 size_t converted_size
= 0;
492 tmp_ctx
= talloc_new(mem_ctx
);
493 if (tmp_ctx
== NULL
) {
497 rc
= asn1_create_element(ctl
->asn1_desc
,
498 "CATALOG.CatalogMemberInfo",
500 if (rc
!= ASN1_SUCCESS
) {
501 DBG_ERR("Failed to create element for "
502 "CATALOG.CatalogMemberInfo: %s\n",
507 rc
= asn1_der_decoding(&member_info
,
511 if (rc
!= ASN1_SUCCESS
) {
512 DBG_ERR("Failed to decode CATALOG.CatalogMemberInfo: %s - %s",
518 rc
= mscat_asn1_read_value(mem_ctx
,
522 if (rc
!= ASN1_SUCCESS
) {
523 DBG_ERR("Failed to read 'name': %s\n",
528 rc
= mscat_asn1_read_value(mem_ctx
,
532 if (rc
!= ASN1_SUCCESS
) {
533 DBG_ERR("Failed to read 'id': %s\n",
538 ok
= convert_string_talloc(mem_ctx
,
550 *pid
= RSVAL(id_blob
.data
, 0);
554 talloc_free(tmp_ctx
);
559 static int ctl_spc_pe_image_data(struct mscat_ctl
*ctl
,
564 char error_string
[ASN1_MAX_ERROR_DESCRIPTION_SIZE
] = {0};
565 ASN1_TYPE spc_pe_image_data
= ASN1_TYPE_EMPTY
;
566 DATA_BLOB flags_blob
= data_blob_null
;
567 DATA_BLOB choice_blob
= data_blob_null
;
573 tmp_ctx
= talloc_new(mem_ctx
);
574 if (tmp_ctx
== NULL
) {
578 rc
= asn1_create_element(ctl
->asn1_desc
,
579 "CATALOG.SpcPEImageData",
581 if (rc
!= ASN1_SUCCESS
) {
582 DBG_ERR("Failed to create element for "
583 "CATALOG.SpcPEImageData: %s\n",
588 rc
= asn1_der_decoding(&spc_pe_image_data
,
592 if (rc
!= ASN1_SUCCESS
) {
593 DBG_ERR("Failed to decode CATALOG.SpcPEImageData: %s - %s",
599 rc
= mscat_asn1_read_value(tmp_ctx
,
603 if (rc
== ASN1_SUCCESS
) {
604 uint32_t flags
= RIVAL(flags_blob
.data
, 0);
606 DBG_ERR(">>> SPC_PE_IMAGE_DATA FLAGS=0x%08x",
609 DBG_ERR("Failed to parse 'flags' in CATALOG.SpcPEImageData - %s",
614 rc
= mscat_asn1_read_value(tmp_ctx
,
618 if (rc
!= ASN1_SUCCESS
) {
619 DBG_ERR("Failed to parse 'link' in CATALOG.SpcPEImageData - %s",
624 cmp
= strncmp((char *)choice_blob
.data
, "url", choice_blob
.length
);
626 /* Never seen in a printer catalog file yet */
627 DBG_INFO("Please report a Samba bug and attach the catalog "
631 cmp
= strncmp((char *)choice_blob
.data
, "moniker", choice_blob
.length
);
633 /* Never seen in a printer catalog file yet */
634 DBG_INFO("Please report a Samba bug and attach the catalog "
638 cmp
= strncmp((char *)choice_blob
.data
, "file", choice_blob
.length
);
643 rc
= mscat_asn1_read_value(tmp_ctx
,
647 if (rc
!= ASN1_SUCCESS
) {
651 link
= talloc_asprintf(tmp_ctx
, "link.file.%s", (char *)choice_blob
.data
);
657 rc
= mscat_asn1_read_value(tmp_ctx
,
661 if (rc
!= ASN1_SUCCESS
) {
662 DBG_ERR("Failed to read '%s' - %s",
669 cmp
= strncmp((char *)choice_blob
.data
, "unicode", choice_blob
.length
);
671 size_t converted_size
= 0;
674 ok
= convert_string_talloc(tmp_ctx
,
687 cmp
= strncmp((char *)choice_blob
.data
, "ascii", choice_blob
.length
);
689 file
= talloc_strndup(tmp_ctx
,
690 (char *)file_blob
.data
,
700 *pfile
= talloc_move(mem_ctx
, &file
);
705 talloc_free(tmp_ctx
);
709 static int ctl_spc_indirect_data(struct mscat_ctl
*ctl
,
712 enum mscat_mac_algorithm
*pmac_algorithm
,
714 size_t *pdigest_size
)
716 char error_string
[ASN1_MAX_ERROR_DESCRIPTION_SIZE
] = {0};
717 ASN1_TYPE spc_indirect_data
= ASN1_TYPE_EMPTY
;
719 enum mscat_mac_algorithm mac_algorithm
= MSCAT_MAC_UNKNOWN
;
720 const char *oid
= NULL
;
721 DATA_BLOB data_value_blob
= data_blob_null
;
722 DATA_BLOB digest_parameters_blob
= data_blob_null
;
723 DATA_BLOB digest_blob
= data_blob_null
;
727 tmp_ctx
= talloc_new(mem_ctx
);
728 if (tmp_ctx
== NULL
) {
732 rc
= asn1_create_element(ctl
->asn1_desc
,
733 "CATALOG.SpcIndirectData",
735 if (rc
!= ASN1_SUCCESS
) {
736 DBG_ERR("Failed to create element for "
737 "CATALOG.SpcIndirectData: %s\n",
742 rc
= asn1_der_decoding(&spc_indirect_data
,
746 if (rc
!= ASN1_SUCCESS
) {
747 DBG_ERR("Failed to decode CATALOG.SpcIndirectData: %s - %s",
753 oid
= mscat_asn1_get_oid(tmp_ctx
,
760 rc
= mscat_asn1_read_value(tmp_ctx
,
764 if (rc
!= ASN1_SUCCESS
) {
765 DBG_ERR("Failed to find data.value in SpcIndirectData: %s\n",
770 ok
= mscat_asn1_oid_equal(oid
, SPC_PE_IMAGE_DATA_OBJID
);
774 rc
= ctl_spc_pe_image_data(ctl
,
782 /* Just returns <<<Obsolete>>> as file */
783 DBG_NOTICE(">>> LINK: %s",
787 oid
= mscat_asn1_get_oid(tmp_ctx
,
789 "messageDigest.digestAlgorithm.algorithm");
794 rc
= mscat_asn1_read_value(tmp_ctx
,
796 "messageDigest.digestAlgorithm.parameters",
797 &digest_parameters_blob
);
798 if (rc
== ASN1_SUCCESS
) {
799 /* Make sure we don't have garbage */
802 if (digest_parameters_blob
.length
!= ASN1_NULL_DATA_SIZE
) {
806 cmp
= memcmp(digest_parameters_blob
.data
,
808 digest_parameters_blob
.length
);
813 } else if (rc
!= ASN1_ELEMENT_NOT_FOUND
) {
814 DBG_ERR("Failed to read 'messageDigest.digestAlgorithm.parameters': %s\n",
819 ok
= mscat_asn1_oid_equal(oid
, HASH_SHA1_OBJID
);
821 mac_algorithm
= MSCAT_MAC_SHA1
;
824 ok
= mscat_asn1_oid_equal(oid
, HASH_SHA256_OBJID
);
826 mac_algorithm
= MSCAT_MAC_SHA256
;
829 if (mac_algorithm
!= MSCAT_MAC_UNKNOWN
&&
830 mac_algorithm
!= MSCAT_MAC_NULL
) {
831 rc
= mscat_asn1_read_value(tmp_ctx
,
833 "messageDigest.digest",
835 if (rc
!= ASN1_SUCCESS
) {
836 DBG_ERR("Failed to find messageDigest.digest in "
837 "SpcIndirectData: %s\n",
843 *pmac_algorithm
= mac_algorithm
;
844 *pdigest
= talloc_move(mem_ctx
, &digest_blob
.data
);
845 *pdigest_size
= digest_blob
.length
;
849 talloc_free(tmp_ctx
);
853 static int ctl_get_member_attributes(struct mscat_ctl
*ctl
,
856 struct mscat_ctl_member
*m
)
864 tmp_ctx
= talloc_new(mem_ctx
);
865 if (tmp_ctx
== NULL
) {
869 el1
= talloc_asprintf(tmp_ctx
,
870 "members.?%u.attributes",
876 rc
= asn1_number_of_elements(ctl
->tree_ctl
,
879 if (rc
!= ASN1_SUCCESS
) {
883 for (i
= 0; i
< count
; i
++) {
884 int content_start
= 0;
892 el2
= talloc_asprintf(tmp_ctx
,
893 "%s.?%d.contentType",
901 oid
= mscat_asn1_get_oid(tmp_ctx
,
910 /* FIXME Looks like this is always 1 */
911 el2
= talloc_asprintf(tmp_ctx
,
920 DBG_DEBUG("Decode element (startEnd) %s",
923 rc
= asn1_der_decoding_startEnd(ctl
->tree_ctl
,
929 if (rc
!= ASN1_SUCCESS
) {
932 if (content_start
< content_end
) {
935 content_len
= content_end
- content_start
+ 1;
937 DBG_DEBUG("Content data_blob length: %zu",
940 content
= data_blob_talloc_zero(tmp_ctx
, content_len
);
941 if (content
.data
== NULL
) {
946 &ctl
->raw_ctl
.data
[content_start
],
949 ok
= mscat_asn1_oid_equal(oid
, CAT_NAME_VALUE_OBJID
);
956 rc
= ctl_parse_name_value(ctl
,
966 DBG_DEBUG("Parsed NameValue: name=%s, flags=%u, value=%s",
971 cmp
= strcmp(name
, "File");
973 m
->file
.name
= talloc_move(m
, &value
);
974 m
->file
.flags
= flags
;
979 cmp
= strcmp(name
, "OSAttr");
981 m
->osattr
.value
= talloc_move(m
, &value
);
982 m
->osattr
.flags
= flags
;
988 ok
= mscat_asn1_oid_equal(oid
, CAT_MEMBERINFO_OBJID
);
993 rc
= ctl_parse_member_info(ctl
,
1002 m
->info
.guid
= talloc_move(m
, &name
);
1008 ok
= mscat_asn1_oid_equal(oid
, SPC_INDIRECT_DATA_OBJID
);
1010 rc
= ctl_spc_indirect_data(ctl
,
1015 &m
->mac
.digest_size
);
1026 talloc_free(tmp_ctx
);
1030 int mscat_ctl_get_member(struct mscat_ctl
*ctl
,
1031 TALLOC_CTX
*mem_ctx
,
1033 struct mscat_ctl_member
**pmember
)
1035 TALLOC_CTX
*tmp_ctx
;
1036 struct mscat_ctl_member
*m
= NULL
;
1039 tmp_ctx
= talloc_new(mem_ctx
);
1040 if (tmp_ctx
== NULL
) {
1044 m
= talloc_zero(tmp_ctx
, struct mscat_ctl_member
);
1050 if (ctl
->version
== 1) {
1051 m
->checksum
.type
= MSCAT_CHECKSUM_STRING
;
1052 rc
= ctl_get_member_checksum_string(ctl
,
1055 &m
->checksum
.string
,
1057 } else if (ctl
->version
== 2) {
1058 m
->checksum
.type
= MSCAT_CHECKSUM_BLOB
;
1059 rc
= ctl_get_member_checksum_blob(ctl
,
1069 rc
= ctl_get_member_attributes(ctl
,
1077 *pmember
= talloc_move(mem_ctx
, &m
);
1081 talloc_free(tmp_ctx
);
1085 int mscat_ctl_get_member_count(struct mscat_ctl
*ctl
)
1090 rc
= asn1_number_of_elements(ctl
->tree_ctl
,
1093 if (rc
!= ASN1_SUCCESS
) {
1100 int mscat_ctl_get_attribute(struct mscat_ctl
*ctl
,
1101 TALLOC_CTX
*mem_ctx
,
1103 struct mscat_ctl_attribute
**pattribute
)
1105 TALLOC_CTX
*tmp_ctx
;
1106 const char *el1
= NULL
;
1107 const char *el2
= NULL
;
1108 const char *oid
= NULL
;
1112 struct mscat_ctl_attribute
*a
= NULL
;
1113 DATA_BLOB encapsulated_data_blob
= data_blob_null
;
1116 tmp_ctx
= talloc_new(mem_ctx
);
1117 if (tmp_ctx
== NULL
) {
1121 a
= talloc_zero(tmp_ctx
, struct mscat_ctl_attribute
);
1127 el1
= talloc_asprintf(tmp_ctx
,
1128 "attributes.?%u.dataId",
1135 oid
= mscat_asn1_get_oid(tmp_ctx
,
1143 el2
= talloc_asprintf(tmp_ctx
,
1144 "attributes.?%u.encapsulated_data",
1151 rc
= mscat_asn1_read_value(tmp_ctx
,
1154 &encapsulated_data_blob
);
1155 if (rc
!= ASN1_SUCCESS
) {
1159 rc
= ctl_parse_name_value(ctl
,
1161 &encapsulated_data_blob
,
1169 a
->name
= talloc_move(a
, &name
);
1171 a
->value
= talloc_move(a
, &value
);
1173 *pattribute
= talloc_move(mem_ctx
, &a
);
1177 talloc_free(tmp_ctx
);
1181 int mscat_ctl_get_attribute_count(struct mscat_ctl
*ctl
)
1186 rc
= asn1_number_of_elements(ctl
->tree_ctl
,
1189 if (rc
!= ASN1_SUCCESS
) {