docs: document SUPPORTS_BLOCK_REFCOUNTING for share:fake_fscaps
[samba4-gss.git] / lib / mscat / mscat_ctl.c
blob292aa9aa6d58e186248017640725a909583fb418
1 /*
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/>.
18 #include <errno.h>
19 #include <string.h>
20 #include <stdint.h>
22 #include <util/debug.h>
23 #include <util/byteorder.h>
24 #include <util/data_blob.h>
25 #include <charset.h>
27 #include "mscat.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[];
49 struct mscat_ctl {
50 int version;
51 asn1_node asn1_desc;
52 asn1_node tree_ctl;
53 gnutls_datum_t raw_ctl;
56 static char *mscat_asn1_get_oid(TALLOC_CTX *mem_ctx,
57 asn1_node root,
58 const char *oid_name)
60 char oid_str[32] = {0};
61 int oid_len = sizeof(oid_str);
62 int rc;
64 rc = asn1_read_value(root,
65 oid_name,
66 oid_str,
67 &oid_len);
68 if (rc != ASN1_SUCCESS) {
69 DBG_ERR("Failed to read value '%s': %s\n",
70 oid_name,
71 asn1_strerror(rc));
72 return NULL;
75 return talloc_strndup(mem_ctx, oid_str, oid_len);
78 static bool mscat_asn1_oid_equal(const char *o1, const char *o2)
80 int cmp;
82 cmp = strcmp(o1, o2);
83 if (cmp != 0) {
84 return false;
87 return true;
90 static int mscat_asn1_read_value(TALLOC_CTX *mem_ctx,
91 asn1_node root,
92 const char *name,
93 DATA_BLOB *blob)
95 DATA_BLOB tmp = data_blob_null;
96 unsigned int etype = ASN1_ETYPE_INVALID;
97 int tmp_len = 0;
98 size_t len;
99 int rc;
101 rc = asn1_read_value_type(root, name, NULL, &tmp_len, &etype);
102 if (rc != ASN1_SUCCESS) {
103 return rc;
105 len = tmp_len;
107 if (etype == ASN1_ETYPE_BIT_STRING) {
108 if (len + 7 < len) {
109 return -1;
111 len = (len + 7) / 8;
114 if (len == 0) {
115 *blob = data_blob_null;
116 return 0;
119 if (len + 1 < len) {
120 return -1;
122 tmp = data_blob_talloc_zero(mem_ctx, len + 1);
123 if (tmp.data == NULL) {
124 return -1;
127 rc = asn1_read_value(root,
128 name,
129 tmp.data,
130 &tmp_len);
131 if (rc != ASN1_SUCCESS) {
132 data_blob_free(&tmp);
133 return rc;
135 len = tmp_len;
137 if (etype == ASN1_ETYPE_BIT_STRING) {
138 if (len + 7 < len) {
139 return -1;
141 len = (len + 7) / 8;
143 tmp.length = len;
145 *blob = tmp;
147 return 0;
150 static int mscat_ctl_cleanup(struct mscat_ctl *ctl)
152 if (ctl->asn1_desc != NULL) {
153 asn1_delete_structure(&ctl->asn1_desc);
156 return 0;
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;
163 int rc;
165 cat_ctl = talloc_zero(mem_ctx, struct mscat_ctl);
166 if (cat_ctl == NULL) {
167 return 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,
175 &cat_ctl->asn1_desc,
176 error_string);
177 if (rc != ASN1_SUCCESS) {
178 talloc_free(cat_ctl);
179 DBG_ERR("Failed to create parser tree: %s - %s\n",
180 asn1_strerror(rc),
181 error_string);
182 return NULL;
185 return cat_ctl;
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;
193 char *oid;
194 bool ok;
195 int rc;
197 rc = gnutls_pkcs7_get_embedded_data(pkcs7->c,
198 GNUTLS_PKCS7_EDATA_GET_RAW,
199 &ctl->raw_ctl);
200 if (rc != GNUTLS_E_SUCCESS) {
201 DBG_ERR("Failed to get embedded data from pkcs7: %s\n",
202 gnutls_strerror(rc));
203 return -1;
206 rc = asn1_create_element(ctl->asn1_desc,
207 "CATALOG.CertTrustList",
208 &ctl->tree_ctl);
209 if (rc != ASN1_SUCCESS) {
210 DBG_ERR("Failed to create CertTrustList ASN.1 element - %s\n",
211 asn1_strerror(rc));
212 return -1;
215 rc = asn1_der_decoding(&ctl->tree_ctl,
216 ctl->raw_ctl.data,
217 ctl->raw_ctl.size,
218 error_string);
219 if (rc != ASN1_SUCCESS) {
220 DBG_ERR("Failed to parse ASN.1 CertTrustList: %s - %s\n",
221 asn1_strerror(rc),
222 error_string);
223 return -1;
226 tmp_ctx = talloc_new(ctl);
227 if (tmp_ctx == NULL) {
228 return -1;
231 oid = mscat_asn1_get_oid(tmp_ctx,
232 ctl->tree_ctl,
233 "catalogListId.oid");
234 if (oid == NULL) {
235 rc = -1;
236 goto done;
239 ok = mscat_asn1_oid_equal(oid, CATALOG_LIST_OBJOID);
240 if (!ok) {
241 DBG_ERR("Invalid oid (%s), expected CATALOG_LIST_OBJOID\n",
242 oid);
243 rc = -1;
244 goto done;
246 talloc_free(oid);
248 oid = mscat_asn1_get_oid(tmp_ctx,
249 ctl->tree_ctl,
250 "catalogListMemberId.oid");
251 if (oid == NULL) {
252 rc = -1;
253 goto done;
256 ok = mscat_asn1_oid_equal(oid, CATALOG_LIST_MEMBER_V2_OBJOID);
257 if (ok) {
258 ctl->version = 2;
259 } else {
260 ok = mscat_asn1_oid_equal(oid, CATALOG_LIST_MEMBER_OBJOID);
261 if (ok) {
262 ctl->version = 1;
263 } else {
264 DBG_ERR("Invalid oid (%s), expected "
265 "CATALOG_LIST_MEMBER_OBJOID\n",
266 oid);
267 rc = -1;
268 goto done;
272 rc = 0;
273 done:
274 talloc_free(tmp_ctx);
275 return rc;
278 static int ctl_get_member_checksum_string(struct mscat_ctl *ctl,
279 TALLOC_CTX *mem_ctx,
280 unsigned int idx,
281 const char **pchecksum,
282 size_t *pchecksum_size)
284 TALLOC_CTX *tmp_ctx;
285 DATA_BLOB chksum_ucs2 = data_blob_null;
286 size_t converted_size = 0;
287 char *checksum = NULL;
288 char *element = NULL;
289 int rc = -1;
290 bool ok;
292 tmp_ctx = talloc_new(mem_ctx);
293 if (tmp_ctx == NULL) {
294 return -1;
297 element = talloc_asprintf(tmp_ctx,
298 "members.?%u.checksum",
299 idx);
300 if (element == NULL) {
301 goto done;
304 rc = mscat_asn1_read_value(tmp_ctx,
305 ctl->tree_ctl,
306 element,
307 &chksum_ucs2);
308 talloc_free(element);
309 if (rc != 0) {
310 goto done;
313 ok = convert_string_talloc(mem_ctx,
314 CH_UTF16LE,
315 CH_UNIX,
316 chksum_ucs2.data,
317 chksum_ucs2.length,
318 &checksum,
319 &converted_size);
320 if (!ok) {
321 rc = -1;
322 goto done;
325 *pchecksum_size = strlen(checksum) + 1;
326 *pchecksum = talloc_move(mem_ctx, &checksum);
328 rc = 0;
329 done:
330 talloc_free(tmp_ctx);
331 return rc;
334 static int ctl_get_member_checksum_blob(struct mscat_ctl *ctl,
335 TALLOC_CTX *mem_ctx,
336 unsigned int idx,
337 uint8_t **pchecksum,
338 size_t *pchecksum_size)
340 TALLOC_CTX *tmp_ctx;
341 DATA_BLOB chksum = data_blob_null;
342 char *element = NULL;
343 int rc = -1;
345 tmp_ctx = talloc_new(mem_ctx);
346 if (tmp_ctx == NULL) {
347 return -1;
350 element = talloc_asprintf(tmp_ctx,
351 "members.?%u.checksum",
352 idx);
353 if (element == NULL) {
354 goto done;
357 rc = mscat_asn1_read_value(tmp_ctx,
358 ctl->tree_ctl,
359 element,
360 &chksum);
361 talloc_free(element);
362 if (rc != 0) {
363 goto done;
366 *pchecksum = talloc_move(mem_ctx, &chksum.data);
367 *pchecksum_size = chksum.length;
369 rc = 0;
370 done:
371 talloc_free(tmp_ctx);
372 return rc;
375 static int ctl_parse_name_value(struct mscat_ctl *ctl,
376 TALLOC_CTX *mem_ctx,
377 DATA_BLOB *content,
378 char **pname,
379 uint32_t *pflags,
380 char **pvalue)
382 char error_string[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = {0};
383 asn1_node name_value = NULL;
384 TALLOC_CTX *tmp_ctx;
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;
389 bool ok;
390 int rc;
392 tmp_ctx = talloc_new(mem_ctx);
393 if (tmp_ctx == NULL) {
394 return -1;
397 rc = asn1_create_element(ctl->asn1_desc,
398 "CATALOG.CatalogNameValue",
399 &name_value);
400 if (rc != ASN1_SUCCESS) {
401 DBG_ERR("Failed to create element for "
402 "CATALOG.CatalogNameValue: %s\n",
403 asn1_strerror(rc));
404 goto done;
407 rc = asn1_der_decoding(&name_value,
408 content->data,
409 content->length,
410 error_string);
411 if (rc != ASN1_SUCCESS) {
412 DBG_ERR("Failed to decode CATALOG.CatalogNameValue: %s - %s\n",
413 asn1_strerror(rc),
414 error_string);
415 goto done;
418 rc = mscat_asn1_read_value(mem_ctx,
419 name_value,
420 "name",
421 &name_blob);
422 if (rc != ASN1_SUCCESS) {
423 DBG_ERR("Failed to read 'name': %s\n",
424 asn1_strerror(rc));
425 goto done;
428 rc = mscat_asn1_read_value(mem_ctx,
429 name_value,
430 "flags",
431 &flags_blob);
432 if (rc != ASN1_SUCCESS) {
433 DBG_ERR("Failed to read 'flags': %s\n",
434 asn1_strerror(rc));
435 goto done;
438 rc = mscat_asn1_read_value(mem_ctx,
439 name_value,
440 "value",
441 &value_blob);
442 if (rc != ASN1_SUCCESS) {
443 DBG_ERR("Failed to read 'value': %s\n",
444 asn1_strerror(rc));
445 goto done;
448 ok = convert_string_talloc(mem_ctx,
449 CH_UTF16BE,
450 CH_UNIX,
451 name_blob.data,
452 name_blob.length,
453 pname,
454 &converted_size);
455 if (!ok) {
456 rc = ASN1_MEM_ERROR;
457 goto done;
460 *pflags = RIVAL(flags_blob.data, 0);
462 ok = convert_string_talloc(mem_ctx,
463 CH_UTF16LE,
464 CH_UNIX,
465 value_blob.data,
466 value_blob.length,
467 pvalue,
468 &converted_size);
469 if (!ok) {
470 rc = ASN1_MEM_ERROR;
471 goto done;
474 rc = 0;
475 done:
476 talloc_free(tmp_ctx);
477 return rc;
480 static int ctl_parse_member_info(struct mscat_ctl *ctl,
481 TALLOC_CTX *mem_ctx,
482 DATA_BLOB *content,
483 char **pname,
484 uint32_t *pid)
486 char error_string[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = {0};
487 asn1_node member_info = NULL;
488 TALLOC_CTX *tmp_ctx;
489 DATA_BLOB name_blob = data_blob_null;
490 DATA_BLOB id_blob = data_blob_null;
491 size_t converted_size = 0;
492 bool ok;
493 int rc;
495 tmp_ctx = talloc_new(mem_ctx);
496 if (tmp_ctx == NULL) {
497 return -1;
500 rc = asn1_create_element(ctl->asn1_desc,
501 "CATALOG.CatalogMemberInfo",
502 &member_info);
503 if (rc != ASN1_SUCCESS) {
504 DBG_ERR("Failed to create element for "
505 "CATALOG.CatalogMemberInfo: %s\n",
506 asn1_strerror(rc));
507 goto done;
510 rc = asn1_der_decoding(&member_info,
511 content->data,
512 content->length,
513 error_string);
514 if (rc != ASN1_SUCCESS) {
515 DBG_ERR("Failed to decode CATALOG.CatalogMemberInfo: %s - %s\n",
516 asn1_strerror(rc),
517 error_string);
518 goto done;
521 rc = mscat_asn1_read_value(mem_ctx,
522 member_info,
523 "name",
524 &name_blob);
525 if (rc != ASN1_SUCCESS) {
526 DBG_ERR("Failed to read 'name': %s\n",
527 asn1_strerror(rc));
528 goto done;
531 rc = mscat_asn1_read_value(mem_ctx,
532 member_info,
533 "id",
534 &id_blob);
535 if (rc != ASN1_SUCCESS) {
536 DBG_ERR("Failed to read 'id': %s\n",
537 asn1_strerror(rc));
538 goto done;
541 ok = convert_string_talloc(mem_ctx,
542 CH_UTF16BE,
543 CH_UNIX,
544 name_blob.data,
545 name_blob.length,
546 pname,
547 &converted_size);
548 if (!ok) {
549 rc = ASN1_MEM_ERROR;
550 goto done;
553 *pid = RSVAL(id_blob.data, 0);
555 rc = 0;
556 done:
557 talloc_free(tmp_ctx);
558 return rc;
562 static int ctl_spc_pe_image_data(struct mscat_ctl *ctl,
563 TALLOC_CTX *mem_ctx,
564 DATA_BLOB *content,
565 char **pfile)
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;
571 char *file = NULL;
572 TALLOC_CTX *tmp_ctx;
573 int cmp;
574 int rc;
576 tmp_ctx = talloc_new(mem_ctx);
577 if (tmp_ctx == NULL) {
578 return -1;
581 rc = asn1_create_element(ctl->asn1_desc,
582 "CATALOG.SpcPEImageData",
583 &spc_pe_image_data);
584 if (rc != ASN1_SUCCESS) {
585 DBG_ERR("Failed to create element for "
586 "CATALOG.SpcPEImageData: %s\n",
587 asn1_strerror(rc));
588 goto done;
591 rc = asn1_der_decoding(&spc_pe_image_data,
592 content->data,
593 content->length,
594 error_string);
595 if (rc != ASN1_SUCCESS) {
596 DBG_ERR("Failed to decode CATALOG.SpcPEImageData: %s - %s\n",
597 asn1_strerror(rc),
598 error_string);
599 goto done;
602 rc = mscat_asn1_read_value(tmp_ctx,
603 spc_pe_image_data,
604 "flags",
605 &flags_blob);
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",
610 flags);
611 } else {
612 DBG_ERR("Failed to parse 'flags' in CATALOG.SpcPEImageData - %s\n",
613 asn1_strerror(rc));
614 goto done;
617 rc = mscat_asn1_read_value(tmp_ctx,
618 spc_pe_image_data,
619 "link",
620 &choice_blob);
621 if (rc != ASN1_SUCCESS) {
622 DBG_ERR("Failed to parse 'link' in CATALOG.SpcPEImageData - %s\n",
623 asn1_strerror(rc));
624 goto done;
627 cmp = strncmp((char *)choice_blob.data, "url", choice_blob.length);
628 if (cmp == 0) {
629 /* Never seen in a printer catalog file yet */
630 DBG_INFO("Please report a Samba bug and attach the catalog "
631 "file\n");
634 cmp = strncmp((char *)choice_blob.data, "moniker", choice_blob.length);
635 if (cmp == 0) {
636 /* Never seen in a printer catalog file yet */
637 DBG_INFO("Please report a Samba bug and attach the catalog "
638 "file\n");
641 cmp = strncmp((char *)choice_blob.data, "file", choice_blob.length);
642 if (cmp == 0) {
643 DATA_BLOB file_blob;
644 char *link;
646 rc = mscat_asn1_read_value(tmp_ctx,
647 spc_pe_image_data,
648 "link.file",
649 &choice_blob);
650 if (rc != ASN1_SUCCESS) {
651 goto done;
654 link = talloc_asprintf(tmp_ctx, "link.file.%s", (char *)choice_blob.data);
655 if (link == NULL) {
656 rc = -1;
657 goto done;
660 rc = mscat_asn1_read_value(tmp_ctx,
661 spc_pe_image_data,
662 link,
663 &file_blob);
664 if (rc != ASN1_SUCCESS) {
665 DBG_ERR("Failed to read '%s' - %s\n",
666 link,
667 asn1_strerror(rc));
668 rc = -1;
669 goto done;
672 cmp = strncmp((char *)choice_blob.data, "unicode", choice_blob.length);
673 if (cmp == 0) {
674 size_t converted_size = 0;
675 bool ok;
677 ok = convert_string_talloc(tmp_ctx,
678 CH_UTF16BE,
679 CH_UNIX,
680 file_blob.data,
681 file_blob.length,
682 &file,
683 &converted_size);
684 if (!ok) {
685 rc = -1;
686 goto done;
690 cmp = strncmp((char *)choice_blob.data, "ascii", choice_blob.length);
691 if (cmp == 0) {
692 file = talloc_strndup(tmp_ctx,
693 (char *)file_blob.data,
694 file_blob.length);
695 if (file == NULL) {
696 rc = -1;
697 goto done;
702 if (file != NULL) {
703 *pfile = talloc_move(mem_ctx, &file);
706 rc = 0;
707 done:
708 talloc_free(tmp_ctx);
709 return rc;
712 static int ctl_spc_indirect_data(struct mscat_ctl *ctl,
713 TALLOC_CTX *mem_ctx,
714 DATA_BLOB *content,
715 enum mscat_mac_algorithm *pmac_algorithm,
716 uint8_t **pdigest,
717 size_t *pdigest_size)
719 char error_string[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = {0};
720 asn1_node spc_indirect_data = NULL;
721 TALLOC_CTX *tmp_ctx;
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;
727 bool ok;
728 int rc;
730 tmp_ctx = talloc_new(mem_ctx);
731 if (tmp_ctx == NULL) {
732 return -1;
735 rc = asn1_create_element(ctl->asn1_desc,
736 "CATALOG.SpcIndirectData",
737 &spc_indirect_data);
738 if (rc != ASN1_SUCCESS) {
739 DBG_ERR("Failed to create element for "
740 "CATALOG.SpcIndirectData: %s\n",
741 asn1_strerror(rc));
742 goto done;
745 rc = asn1_der_decoding(&spc_indirect_data,
746 content->data,
747 content->length,
748 error_string);
749 if (rc != ASN1_SUCCESS) {
750 DBG_ERR("Failed to decode CATALOG.SpcIndirectData: %s - %s\n",
751 asn1_strerror(rc),
752 error_string);
753 goto done;
756 oid = mscat_asn1_get_oid(tmp_ctx,
757 spc_indirect_data,
758 "data.type");
759 if (oid == NULL) {
760 goto done;
763 rc = mscat_asn1_read_value(tmp_ctx,
764 spc_indirect_data,
765 "data.value",
766 &data_value_blob);
767 if (rc != ASN1_SUCCESS) {
768 DBG_ERR("Failed to find data.value in SpcIndirectData: %s\n",
769 asn1_strerror(rc));
770 goto done;
773 ok = mscat_asn1_oid_equal(oid, SPC_PE_IMAGE_DATA_OBJID);
774 if (ok) {
775 char *file = NULL;
777 rc = ctl_spc_pe_image_data(ctl,
778 tmp_ctx,
779 &data_value_blob,
780 &file);
781 if (rc != 0) {
782 goto done;
785 /* Just returns <<<Obsolete>>> as file */
786 DBG_NOTICE(">>> LINK: %s\n",
787 file);
790 oid = mscat_asn1_get_oid(tmp_ctx,
791 spc_indirect_data,
792 "messageDigest.digestAlgorithm.algorithm");
793 if (oid == NULL) {
794 goto done;
797 rc = mscat_asn1_read_value(tmp_ctx,
798 spc_indirect_data,
799 "messageDigest.digestAlgorithm.parameters",
800 &digest_parameters_blob);
801 if (rc == ASN1_SUCCESS) {
802 /* Make sure we don't have garbage */
803 int cmp;
805 if (digest_parameters_blob.length != ASN1_NULL_DATA_SIZE) {
806 rc = -1;
807 goto done;
809 cmp = memcmp(digest_parameters_blob.data,
810 ASN1_NULL_DATA,
811 digest_parameters_blob.length);
812 if (cmp != 0) {
813 rc = -1;
814 goto done;
816 } else if (rc != ASN1_ELEMENT_NOT_FOUND) {
817 DBG_ERR("Failed to read 'messageDigest.digestAlgorithm.parameters': %s\n",
818 asn1_strerror(rc));
819 goto done;
822 ok = mscat_asn1_oid_equal(oid, HASH_SHA1_OBJID);
823 if (ok) {
824 mac_algorithm = MSCAT_MAC_SHA1;
827 ok = mscat_asn1_oid_equal(oid, HASH_SHA256_OBJID);
828 if (ok) {
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,
835 spc_indirect_data,
836 "messageDigest.digest",
837 &digest_blob);
838 if (rc != ASN1_SUCCESS) {
839 DBG_ERR("Failed to find messageDigest.digest in "
840 "SpcIndirectData: %s\n",
841 asn1_strerror(rc));
842 goto done;
846 *pmac_algorithm = mac_algorithm;
847 *pdigest = talloc_move(mem_ctx, &digest_blob.data);
848 *pdigest_size = digest_blob.length;
850 rc = 0;
851 done:
852 talloc_free(tmp_ctx);
853 return rc;
856 static int ctl_get_member_attributes(struct mscat_ctl *ctl,
857 TALLOC_CTX *mem_ctx,
858 unsigned int idx,
859 struct mscat_ctl_member *m)
861 TALLOC_CTX *tmp_ctx;
862 char *el1 = NULL;
863 int count = 0;
864 int i;
865 int rc = -1;
867 tmp_ctx = talloc_new(mem_ctx);
868 if (tmp_ctx == NULL) {
869 return -1;
872 el1 = talloc_asprintf(tmp_ctx,
873 "members.?%u.attributes",
874 idx);
875 if (el1 == NULL) {
876 goto done;
879 rc = asn1_number_of_elements(ctl->tree_ctl,
880 el1,
881 &count);
882 if (rc != ASN1_SUCCESS) {
883 goto done;
886 for (i = 0; i < count; i++) {
887 int content_start = 0;
888 int content_end = 0;
889 size_t content_len;
890 DATA_BLOB content;
891 char *el2;
892 char *oid;
893 bool ok;
895 el2 = talloc_asprintf(tmp_ctx,
896 "%s.?%d.contentType",
897 el1,
898 i + 1);
899 if (el2 == NULL) {
900 rc = -1;
901 goto done;
904 oid = mscat_asn1_get_oid(tmp_ctx,
905 ctl->tree_ctl,
906 el2);
907 talloc_free(el2);
908 if (oid == NULL) {
909 rc = -1;
910 goto done;
913 /* FIXME Looks like this is always 1 */
914 el2 = talloc_asprintf(tmp_ctx,
915 "%s.?%d.content.?1",
916 el1,
917 i + 1);
918 if (el2 == NULL) {
919 rc = -1;
920 goto done;
923 DBG_DEBUG("Decode element (startEnd) %s\n",
924 el2);
926 rc = asn1_der_decoding_startEnd(ctl->tree_ctl,
927 ctl->raw_ctl.data,
928 ctl->raw_ctl.size,
929 el2,
930 &content_start,
931 &content_end);
932 if (rc != ASN1_SUCCESS) {
933 goto done;
935 if (content_start < content_end) {
936 goto done;
938 content_len = content_end - content_start + 1;
940 DBG_DEBUG("Content data_blob length: %zu\n",
941 content_len);
943 content = data_blob_talloc_zero(tmp_ctx, content_len);
944 if (content.data == NULL) {
945 rc = -1;
946 goto done;
948 memcpy(content.data,
949 &ctl->raw_ctl.data[content_start],
950 content_len);
952 ok = mscat_asn1_oid_equal(oid, CAT_NAME_VALUE_OBJID);
953 if (ok) {
954 char *name;
955 uint32_t flags;
956 char *value;
957 int cmp;
959 rc = ctl_parse_name_value(ctl,
960 tmp_ctx,
961 &content,
962 &name,
963 &flags,
964 &value);
965 if (rc != 0) {
966 goto done;
969 DBG_DEBUG("Parsed NameValue: name=%s, flags=%u, value=%s\n",
970 name,
971 flags,
972 value);
974 cmp = strcmp(name, "File");
975 if (cmp == 0) {
976 m->file.name = talloc_move(m, &value);
977 m->file.flags = flags;
979 continue;
982 cmp = strcmp(name, "OSAttr");
983 if (cmp == 0) {
984 m->osattr.value = talloc_move(m, &value);
985 m->osattr.flags = flags;
987 continue;
991 ok = mscat_asn1_oid_equal(oid, CAT_MEMBERINFO_OBJID);
992 if (ok) {
993 char *name = NULL;
994 uint32_t id = 0;
996 rc = ctl_parse_member_info(ctl,
997 tmp_ctx,
998 &content,
999 &name,
1000 &id);
1001 if (rc != 0) {
1002 goto done;
1005 m->info.guid = talloc_move(m, &name);
1006 m->info.id = id;
1008 continue;
1011 ok = mscat_asn1_oid_equal(oid, SPC_INDIRECT_DATA_OBJID);
1012 if (ok) {
1013 rc = ctl_spc_indirect_data(ctl,
1015 &content,
1016 &m->mac.type,
1017 &m->mac.digest,
1018 &m->mac.digest_size);
1019 if (rc != 0) {
1020 goto done;
1023 continue;
1027 rc = 0;
1028 done:
1029 talloc_free(tmp_ctx);
1030 return rc;
1033 int mscat_ctl_get_member(struct mscat_ctl *ctl,
1034 TALLOC_CTX *mem_ctx,
1035 unsigned int idx,
1036 struct mscat_ctl_member **pmember)
1038 TALLOC_CTX *tmp_ctx;
1039 struct mscat_ctl_member *m = NULL;
1040 int rc = -1;
1042 tmp_ctx = talloc_new(mem_ctx);
1043 if (tmp_ctx == NULL) {
1044 return -1;
1047 m = talloc_zero(tmp_ctx, struct mscat_ctl_member);
1048 if (m == NULL) {
1049 rc = -1;
1050 goto done;
1053 if (ctl->version == 1) {
1054 m->checksum.type = MSCAT_CHECKSUM_STRING;
1055 rc = ctl_get_member_checksum_string(ctl,
1057 idx,
1058 &m->checksum.string,
1059 &m->checksum.size);
1060 } else if (ctl->version == 2) {
1061 m->checksum.type = MSCAT_CHECKSUM_BLOB;
1062 rc = ctl_get_member_checksum_blob(ctl,
1064 idx,
1065 &m->checksum.blob,
1066 &m->checksum.size);
1068 if (rc != 0) {
1069 goto done;
1072 rc = ctl_get_member_attributes(ctl,
1073 mem_ctx,
1074 idx,
1076 if (rc != 0) {
1077 goto done;
1080 *pmember = talloc_move(mem_ctx, &m);
1082 rc = 0;
1083 done:
1084 talloc_free(tmp_ctx);
1085 return rc;
1088 int mscat_ctl_get_member_count(struct mscat_ctl *ctl)
1090 int count = 0;
1091 int rc;
1093 rc = asn1_number_of_elements(ctl->tree_ctl,
1094 "members",
1095 &count);
1096 if (rc != ASN1_SUCCESS) {
1097 return -1;
1100 return count;
1103 int mscat_ctl_get_attribute(struct mscat_ctl *ctl,
1104 TALLOC_CTX *mem_ctx,
1105 unsigned int idx,
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;
1112 char *name = NULL;
1113 uint32_t flags = 0;
1114 char *value = NULL;
1115 struct mscat_ctl_attribute *a = NULL;
1116 DATA_BLOB encapsulated_data_blob = data_blob_null;
1117 int rc;
1119 tmp_ctx = talloc_new(mem_ctx);
1120 if (tmp_ctx == NULL) {
1121 return -1;
1124 a = talloc_zero(tmp_ctx, struct mscat_ctl_attribute);
1125 if (a == NULL) {
1126 rc = -1;
1127 goto done;
1130 el1 = talloc_asprintf(tmp_ctx,
1131 "attributes.?%u.dataId",
1132 idx);
1133 if (el1 == NULL) {
1134 rc = -1;
1135 goto done;
1138 oid = mscat_asn1_get_oid(tmp_ctx,
1139 ctl->tree_ctl,
1140 el1);
1141 if (oid == NULL) {
1142 rc = -1;
1143 goto done;
1146 el2 = talloc_asprintf(tmp_ctx,
1147 "attributes.?%u.encapsulated_data",
1148 idx);
1149 if (el2 == NULL) {
1150 rc = -1;
1151 goto done;
1154 rc = mscat_asn1_read_value(tmp_ctx,
1155 ctl->tree_ctl,
1156 el2,
1157 &encapsulated_data_blob);
1158 if (rc != ASN1_SUCCESS) {
1159 goto done;
1162 rc = ctl_parse_name_value(ctl,
1163 tmp_ctx,
1164 &encapsulated_data_blob,
1165 &name,
1166 &flags,
1167 &value);
1168 if (rc != 0) {
1169 goto done;
1172 a->name = talloc_move(a, &name);
1173 a->flags = flags;
1174 a->value = talloc_move(a, &value);
1176 *pattribute = talloc_move(mem_ctx, &a);
1178 rc = 0;
1179 done:
1180 talloc_free(tmp_ctx);
1181 return rc;
1184 int mscat_ctl_get_attribute_count(struct mscat_ctl *ctl)
1186 int count = 0;
1187 int rc;
1189 rc = asn1_number_of_elements(ctl->tree_ctl,
1190 "attributes",
1191 &count);
1192 if (rc != ASN1_SUCCESS) {
1193 return -1;
1196 return count;