selftest: don't hardcode '.python3' for extra-python tests
[Samba.git] / lib / mscat / mscat_ctl.c
blob972922c4f75cc69c02dcb13ad3f22469cbbd3122
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_TYPE asn1_desc;
52 ASN1_TYPE 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 len = 0;
98 int rc;
100 rc = asn1_read_value_type(root, name, NULL, &len, &etype);
101 if (rc != ASN1_SUCCESS) {
102 return rc;
105 if (etype == ASN1_ETYPE_BIT_STRING) {
106 if (len + 7 < len) {
107 return -1;
109 len = (len + 7) / 8;
112 if (len == 0) {
113 *blob = data_blob_null;
114 return 0;
117 if (len + 1 < len) {
118 return -1;
120 tmp = data_blob_talloc_zero(mem_ctx, len + 1);
121 if (tmp.data == NULL) {
122 return -1;
125 rc = asn1_read_value(root,
126 name,
127 tmp.data,
128 &len);
129 if (rc != ASN1_SUCCESS) {
130 data_blob_free(&tmp);
131 return rc;
134 if (etype == ASN1_ETYPE_BIT_STRING) {
135 if (len + 7 < len) {
136 return -1;
138 len = (len + 7) / 8;
140 tmp.length = len;
142 *blob = tmp;
144 return 0;
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);
153 return 0;
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;
160 int rc;
162 cat_ctl = talloc_zero(mem_ctx, struct mscat_ctl);
163 if (cat_ctl == NULL) {
164 return 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,
172 &cat_ctl->asn1_desc,
173 error_string);
174 if (rc != ASN1_SUCCESS) {
175 talloc_free(cat_ctl);
176 DBG_ERR("Failed to create parser tree: %s - %s\n",
177 asn1_strerror(rc),
178 error_string);
179 return NULL;
182 return cat_ctl;
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;
190 char *oid;
191 bool ok;
192 int rc;
194 rc = gnutls_pkcs7_get_embedded_data(pkcs7->c,
195 GNUTLS_PKCS7_EDATA_GET_RAW,
196 &ctl->raw_ctl);
197 if (rc != GNUTLS_E_SUCCESS) {
198 DBG_ERR("Failed to get embedded data from pkcs7: %s\n",
199 gnutls_strerror(rc));
200 return -1;
203 rc = asn1_create_element(ctl->asn1_desc,
204 "CATALOG.CertTrustList",
205 &ctl->tree_ctl);
206 if (rc != ASN1_SUCCESS) {
207 DBG_ERR("Failed to create CertTrustList ASN.1 element - %s\n",
208 asn1_strerror(rc));
209 return -1;
212 rc = asn1_der_decoding(&ctl->tree_ctl,
213 ctl->raw_ctl.data,
214 ctl->raw_ctl.size,
215 error_string);
216 if (rc != ASN1_SUCCESS) {
217 DBG_ERR("Failed to parse ASN.1 CertTrustList: %s - %s\n",
218 asn1_strerror(rc),
219 error_string);
220 return -1;
223 tmp_ctx = talloc_new(ctl);
224 if (tmp_ctx == NULL) {
225 return -1;
228 oid = mscat_asn1_get_oid(tmp_ctx,
229 ctl->tree_ctl,
230 "catalogListId.oid");
231 if (oid == NULL) {
232 rc = -1;
233 goto done;
236 ok = mscat_asn1_oid_equal(oid, CATALOG_LIST_OBJOID);
237 if (!ok) {
238 DBG_ERR("Invalid oid (%s), expected CATALOG_LIST_OBJOID",
239 oid);
240 rc = -1;
241 goto done;
243 talloc_free(oid);
245 oid = mscat_asn1_get_oid(tmp_ctx,
246 ctl->tree_ctl,
247 "catalogListMemberId.oid");
248 if (oid == NULL) {
249 rc = -1;
250 goto done;
253 ok = mscat_asn1_oid_equal(oid, CATALOG_LIST_MEMBER_V2_OBJOID);
254 if (ok) {
255 ctl->version = 2;
256 } else {
257 ok = mscat_asn1_oid_equal(oid, CATALOG_LIST_MEMBER_OBJOID);
258 if (ok) {
259 ctl->version = 1;
260 } else {
261 DBG_ERR("Invalid oid (%s), expected "
262 "CATALOG_LIST_MEMBER_OBJOID",
263 oid);
264 rc = -1;
265 goto done;
269 rc = 0;
270 done:
271 talloc_free(tmp_ctx);
272 return rc;
275 static int ctl_get_member_checksum_string(struct mscat_ctl *ctl,
276 TALLOC_CTX *mem_ctx,
277 unsigned int idx,
278 const char **pchecksum,
279 size_t *pchecksum_size)
281 TALLOC_CTX *tmp_ctx;
282 DATA_BLOB chksum_ucs2 = data_blob_null;
283 size_t converted_size = 0;
284 char *checksum = NULL;
285 char *element = NULL;
286 int rc = -1;
287 bool ok;
289 tmp_ctx = talloc_new(mem_ctx);
290 if (tmp_ctx == NULL) {
291 return -1;
294 element = talloc_asprintf(tmp_ctx,
295 "members.?%u.checksum",
296 idx);
297 if (element == NULL) {
298 goto done;
301 rc = mscat_asn1_read_value(tmp_ctx,
302 ctl->tree_ctl,
303 element,
304 &chksum_ucs2);
305 talloc_free(element);
306 if (rc != 0) {
307 goto done;
310 ok = convert_string_talloc(mem_ctx,
311 CH_UTF16LE,
312 CH_UNIX,
313 chksum_ucs2.data,
314 chksum_ucs2.length,
315 (void **)&checksum,
316 &converted_size);
317 if (!ok) {
318 rc = -1;
319 goto done;
322 *pchecksum_size = strlen(checksum) + 1;
323 *pchecksum = talloc_move(mem_ctx, &checksum);
325 rc = 0;
326 done:
327 talloc_free(tmp_ctx);
328 return rc;
331 static int ctl_get_member_checksum_blob(struct mscat_ctl *ctl,
332 TALLOC_CTX *mem_ctx,
333 unsigned int idx,
334 uint8_t **pchecksum,
335 size_t *pchecksum_size)
337 TALLOC_CTX *tmp_ctx;
338 DATA_BLOB chksum = data_blob_null;
339 char *element = NULL;
340 int rc = -1;
342 tmp_ctx = talloc_new(mem_ctx);
343 if (tmp_ctx == NULL) {
344 return -1;
347 element = talloc_asprintf(tmp_ctx,
348 "members.?%u.checksum",
349 idx);
350 if (element == NULL) {
351 goto done;
354 rc = mscat_asn1_read_value(tmp_ctx,
355 ctl->tree_ctl,
356 element,
357 &chksum);
358 talloc_free(element);
359 if (rc != 0) {
360 goto done;
363 *pchecksum = talloc_move(mem_ctx, &chksum.data);
364 *pchecksum_size = chksum.length;
366 rc = 0;
367 done:
368 talloc_free(tmp_ctx);
369 return rc;
372 static int ctl_parse_name_value(struct mscat_ctl *ctl,
373 TALLOC_CTX *mem_ctx,
374 DATA_BLOB *content,
375 char **pname,
376 uint32_t *pflags,
377 char **pvalue)
379 char error_string[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = {0};
380 ASN1_TYPE name_value = ASN1_TYPE_EMPTY;
381 TALLOC_CTX *tmp_ctx;
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;
386 bool ok;
387 int rc;
389 tmp_ctx = talloc_new(mem_ctx);
390 if (tmp_ctx == NULL) {
391 return -1;
394 rc = asn1_create_element(ctl->asn1_desc,
395 "CATALOG.CatalogNameValue",
396 &name_value);
397 if (rc != ASN1_SUCCESS) {
398 DBG_ERR("Failed to create element for "
399 "CATALOG.CatalogNameValue: %s\n",
400 asn1_strerror(rc));
401 goto done;
404 rc = asn1_der_decoding(&name_value,
405 content->data,
406 content->length,
407 error_string);
408 if (rc != ASN1_SUCCESS) {
409 DBG_ERR("Failed to decode CATALOG.CatalogNameValue: %s - %s",
410 asn1_strerror(rc),
411 error_string);
412 goto done;
415 rc = mscat_asn1_read_value(mem_ctx,
416 name_value,
417 "name",
418 &name_blob);
419 if (rc != ASN1_SUCCESS) {
420 DBG_ERR("Failed to read 'name': %s\n",
421 asn1_strerror(rc));
422 goto done;
425 rc = mscat_asn1_read_value(mem_ctx,
426 name_value,
427 "flags",
428 &flags_blob);
429 if (rc != ASN1_SUCCESS) {
430 DBG_ERR("Failed to read 'flags': %s\n",
431 asn1_strerror(rc));
432 goto done;
435 rc = mscat_asn1_read_value(mem_ctx,
436 name_value,
437 "value",
438 &value_blob);
439 if (rc != ASN1_SUCCESS) {
440 DBG_ERR("Failed to read 'value': %s\n",
441 asn1_strerror(rc));
442 goto done;
445 ok = convert_string_talloc(mem_ctx,
446 CH_UTF16BE,
447 CH_UNIX,
448 name_blob.data,
449 name_blob.length,
450 (void **)pname,
451 &converted_size);
452 if (!ok) {
453 rc = ASN1_MEM_ERROR;
454 goto done;
457 *pflags = RIVAL(flags_blob.data, 0);
459 ok = convert_string_talloc(mem_ctx,
460 CH_UTF16LE,
461 CH_UNIX,
462 value_blob.data,
463 value_blob.length,
464 (void **)pvalue,
465 &converted_size);
466 if (!ok) {
467 rc = ASN1_MEM_ERROR;
468 goto done;
471 rc = 0;
472 done:
473 talloc_free(tmp_ctx);
474 return rc;
477 static int ctl_parse_member_info(struct mscat_ctl *ctl,
478 TALLOC_CTX *mem_ctx,
479 DATA_BLOB *content,
480 char **pname,
481 uint32_t *pid)
483 char error_string[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = {0};
484 ASN1_TYPE member_info = ASN1_TYPE_EMPTY;
485 TALLOC_CTX *tmp_ctx;
486 DATA_BLOB name_blob = data_blob_null;
487 DATA_BLOB id_blob = data_blob_null;
488 size_t converted_size = 0;
489 bool ok;
490 int rc;
492 tmp_ctx = talloc_new(mem_ctx);
493 if (tmp_ctx == NULL) {
494 return -1;
497 rc = asn1_create_element(ctl->asn1_desc,
498 "CATALOG.CatalogMemberInfo",
499 &member_info);
500 if (rc != ASN1_SUCCESS) {
501 DBG_ERR("Failed to create element for "
502 "CATALOG.CatalogMemberInfo: %s\n",
503 asn1_strerror(rc));
504 goto done;
507 rc = asn1_der_decoding(&member_info,
508 content->data,
509 content->length,
510 error_string);
511 if (rc != ASN1_SUCCESS) {
512 DBG_ERR("Failed to decode CATALOG.CatalogMemberInfo: %s - %s",
513 asn1_strerror(rc),
514 error_string);
515 goto done;
518 rc = mscat_asn1_read_value(mem_ctx,
519 member_info,
520 "name",
521 &name_blob);
522 if (rc != ASN1_SUCCESS) {
523 DBG_ERR("Failed to read 'name': %s\n",
524 asn1_strerror(rc));
525 goto done;
528 rc = mscat_asn1_read_value(mem_ctx,
529 member_info,
530 "id",
531 &id_blob);
532 if (rc != ASN1_SUCCESS) {
533 DBG_ERR("Failed to read 'id': %s\n",
534 asn1_strerror(rc));
535 goto done;
538 ok = convert_string_talloc(mem_ctx,
539 CH_UTF16BE,
540 CH_UNIX,
541 name_blob.data,
542 name_blob.length,
543 (void **)pname,
544 &converted_size);
545 if (!ok) {
546 rc = ASN1_MEM_ERROR;
547 goto done;
550 *pid = RSVAL(id_blob.data, 0);
552 rc = 0;
553 done:
554 talloc_free(tmp_ctx);
555 return rc;
559 static int ctl_spc_pe_image_data(struct mscat_ctl *ctl,
560 TALLOC_CTX *mem_ctx,
561 DATA_BLOB *content,
562 char **pfile)
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;
568 char *file = NULL;
569 TALLOC_CTX *tmp_ctx;
570 int cmp;
571 int rc;
573 tmp_ctx = talloc_new(mem_ctx);
574 if (tmp_ctx == NULL) {
575 return -1;
578 rc = asn1_create_element(ctl->asn1_desc,
579 "CATALOG.SpcPEImageData",
580 &spc_pe_image_data);
581 if (rc != ASN1_SUCCESS) {
582 DBG_ERR("Failed to create element for "
583 "CATALOG.SpcPEImageData: %s\n",
584 asn1_strerror(rc));
585 goto done;
588 rc = asn1_der_decoding(&spc_pe_image_data,
589 content->data,
590 content->length,
591 error_string);
592 if (rc != ASN1_SUCCESS) {
593 DBG_ERR("Failed to decode CATALOG.SpcPEImageData: %s - %s",
594 asn1_strerror(rc),
595 error_string);
596 goto done;
599 rc = mscat_asn1_read_value(tmp_ctx,
600 spc_pe_image_data,
601 "flags",
602 &flags_blob);
603 if (rc == ASN1_SUCCESS) {
604 uint32_t flags = RIVAL(flags_blob.data, 0);
606 DBG_ERR(">>> SPC_PE_IMAGE_DATA FLAGS=0x%08x",
607 flags);
608 } else {
609 DBG_ERR("Failed to parse 'flags' in CATALOG.SpcPEImageData - %s",
610 asn1_strerror(rc));
611 goto done;
614 rc = mscat_asn1_read_value(tmp_ctx,
615 spc_pe_image_data,
616 "link",
617 &choice_blob);
618 if (rc != ASN1_SUCCESS) {
619 DBG_ERR("Failed to parse 'link' in CATALOG.SpcPEImageData - %s",
620 asn1_strerror(rc));
621 goto done;
624 cmp = strncmp((char *)choice_blob.data, "url", choice_blob.length);
625 if (cmp == 0) {
626 /* Never seen in a printer catalog file yet */
627 DBG_INFO("Please report a Samba bug and attach the catalog "
628 "file\n");
631 cmp = strncmp((char *)choice_blob.data, "moniker", choice_blob.length);
632 if (cmp == 0) {
633 /* Never seen in a printer catalog file yet */
634 DBG_INFO("Please report a Samba bug and attach the catalog "
635 "file\n");
638 cmp = strncmp((char *)choice_blob.data, "file", choice_blob.length);
639 if (cmp == 0) {
640 DATA_BLOB file_blob;
641 char *link;
643 rc = mscat_asn1_read_value(tmp_ctx,
644 spc_pe_image_data,
645 "link.file",
646 &choice_blob);
647 if (rc != ASN1_SUCCESS) {
648 goto done;
651 link = talloc_asprintf(tmp_ctx, "link.file.%s", (char *)choice_blob.data);
652 if (link == NULL) {
653 rc = -1;
654 goto done;
657 rc = mscat_asn1_read_value(tmp_ctx,
658 spc_pe_image_data,
659 link,
660 &file_blob);
661 if (rc != ASN1_SUCCESS) {
662 DBG_ERR("Failed to read '%s' - %s",
663 link,
664 asn1_strerror(rc));
665 rc = -1;
666 goto done;
669 cmp = strncmp((char *)choice_blob.data, "unicode", choice_blob.length);
670 if (cmp == 0) {
671 size_t converted_size = 0;
672 bool ok;
674 ok = convert_string_talloc(tmp_ctx,
675 CH_UTF16BE,
676 CH_UNIX,
677 file_blob.data,
678 file_blob.length,
679 (void **)&file,
680 &converted_size);
681 if (!ok) {
682 rc = -1;
683 goto done;
687 cmp = strncmp((char *)choice_blob.data, "ascii", choice_blob.length);
688 if (cmp == 0) {
689 file = talloc_strndup(tmp_ctx,
690 (char *)file_blob.data,
691 file_blob.length);
692 if (file == NULL) {
693 rc = -1;
694 goto done;
699 if (file != NULL) {
700 *pfile = talloc_move(mem_ctx, &file);
703 rc = 0;
704 done:
705 talloc_free(tmp_ctx);
706 return rc;
709 static int ctl_spc_indirect_data(struct mscat_ctl *ctl,
710 TALLOC_CTX *mem_ctx,
711 DATA_BLOB *content,
712 enum mscat_mac_algorithm *pmac_algorithm,
713 uint8_t **pdigest,
714 size_t *pdigest_size)
716 char error_string[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = {0};
717 ASN1_TYPE spc_indirect_data = ASN1_TYPE_EMPTY;
718 TALLOC_CTX *tmp_ctx;
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;
724 bool ok;
725 int rc;
727 tmp_ctx = talloc_new(mem_ctx);
728 if (tmp_ctx == NULL) {
729 return -1;
732 rc = asn1_create_element(ctl->asn1_desc,
733 "CATALOG.SpcIndirectData",
734 &spc_indirect_data);
735 if (rc != ASN1_SUCCESS) {
736 DBG_ERR("Failed to create element for "
737 "CATALOG.SpcIndirectData: %s\n",
738 asn1_strerror(rc));
739 goto done;
742 rc = asn1_der_decoding(&spc_indirect_data,
743 content->data,
744 content->length,
745 error_string);
746 if (rc != ASN1_SUCCESS) {
747 DBG_ERR("Failed to decode CATALOG.SpcIndirectData: %s - %s",
748 asn1_strerror(rc),
749 error_string);
750 goto done;
753 oid = mscat_asn1_get_oid(tmp_ctx,
754 spc_indirect_data,
755 "data.type");
756 if (oid == NULL) {
757 goto done;
760 rc = mscat_asn1_read_value(tmp_ctx,
761 spc_indirect_data,
762 "data.value",
763 &data_value_blob);
764 if (rc != ASN1_SUCCESS) {
765 DBG_ERR("Failed to find data.value in SpcIndirectData: %s\n",
766 asn1_strerror(rc));
767 goto done;
770 ok = mscat_asn1_oid_equal(oid, SPC_PE_IMAGE_DATA_OBJID);
771 if (ok) {
772 char *file = NULL;
774 rc = ctl_spc_pe_image_data(ctl,
775 tmp_ctx,
776 &data_value_blob,
777 &file);
778 if (rc != 0) {
779 goto done;
782 /* Just returns <<<Obsolete>>> as file */
783 DBG_NOTICE(">>> LINK: %s",
784 file);
787 oid = mscat_asn1_get_oid(tmp_ctx,
788 spc_indirect_data,
789 "messageDigest.digestAlgorithm.algorithm");
790 if (oid == NULL) {
791 goto done;
794 rc = mscat_asn1_read_value(tmp_ctx,
795 spc_indirect_data,
796 "messageDigest.digestAlgorithm.parameters",
797 &digest_parameters_blob);
798 if (rc == ASN1_SUCCESS) {
799 /* Make sure we don't have garbage */
800 int cmp;
802 if (digest_parameters_blob.length != ASN1_NULL_DATA_SIZE) {
803 rc = -1;
804 goto done;
806 cmp = memcmp(digest_parameters_blob.data,
807 ASN1_NULL_DATA,
808 digest_parameters_blob.length);
809 if (cmp != 0) {
810 rc = -1;
811 goto done;
813 } else if (rc != ASN1_ELEMENT_NOT_FOUND) {
814 DBG_ERR("Failed to read 'messageDigest.digestAlgorithm.parameters': %s\n",
815 asn1_strerror(rc));
816 goto done;
819 ok = mscat_asn1_oid_equal(oid, HASH_SHA1_OBJID);
820 if (ok) {
821 mac_algorithm = MSCAT_MAC_SHA1;
824 ok = mscat_asn1_oid_equal(oid, HASH_SHA256_OBJID);
825 if (ok) {
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,
832 spc_indirect_data,
833 "messageDigest.digest",
834 &digest_blob);
835 if (rc != ASN1_SUCCESS) {
836 DBG_ERR("Failed to find messageDigest.digest in "
837 "SpcIndirectData: %s\n",
838 asn1_strerror(rc));
839 goto done;
843 *pmac_algorithm = mac_algorithm;
844 *pdigest = talloc_move(mem_ctx, &digest_blob.data);
845 *pdigest_size = digest_blob.length;
847 rc = 0;
848 done:
849 talloc_free(tmp_ctx);
850 return rc;
853 static int ctl_get_member_attributes(struct mscat_ctl *ctl,
854 TALLOC_CTX *mem_ctx,
855 unsigned int idx,
856 struct mscat_ctl_member *m)
858 TALLOC_CTX *tmp_ctx;
859 char *el1 = NULL;
860 int count = 0;
861 int i;
862 int rc = -1;
864 tmp_ctx = talloc_new(mem_ctx);
865 if (tmp_ctx == NULL) {
866 return -1;
869 el1 = talloc_asprintf(tmp_ctx,
870 "members.?%u.attributes",
871 idx);
872 if (el1 == NULL) {
873 goto done;
876 rc = asn1_number_of_elements(ctl->tree_ctl,
877 el1,
878 &count);
879 if (rc != ASN1_SUCCESS) {
880 goto done;
883 for (i = 0; i < count; i++) {
884 int content_start = 0;
885 int content_end = 0;
886 size_t content_len;
887 DATA_BLOB content;
888 char *el2;
889 char *oid;
890 bool ok;
892 el2 = talloc_asprintf(tmp_ctx,
893 "%s.?%d.contentType",
894 el1,
895 i + 1);
896 if (el2 == NULL) {
897 rc = -1;
898 goto done;
901 oid = mscat_asn1_get_oid(tmp_ctx,
902 ctl->tree_ctl,
903 el2);
904 talloc_free(el2);
905 if (oid == NULL) {
906 rc = -1;
907 goto done;
910 /* FIXME Looks like this is always 1 */
911 el2 = talloc_asprintf(tmp_ctx,
912 "%s.?%d.content.?1",
913 el1,
914 i + 1);
915 if (el2 == NULL) {
916 rc = -1;
917 goto done;
920 DBG_DEBUG("Decode element (startEnd) %s",
921 el2);
923 rc = asn1_der_decoding_startEnd(ctl->tree_ctl,
924 ctl->raw_ctl.data,
925 ctl->raw_ctl.size,
926 el2,
927 &content_start,
928 &content_end);
929 if (rc != ASN1_SUCCESS) {
930 goto done;
932 if (content_start < content_end) {
933 goto done;
935 content_len = content_end - content_start + 1;
937 DBG_DEBUG("Content data_blob length: %zu",
938 content_len);
940 content = data_blob_talloc_zero(tmp_ctx, content_len);
941 if (content.data == NULL) {
942 rc = -1;
943 goto done;
945 memcpy(content.data,
946 &ctl->raw_ctl.data[content_start],
947 content_len);
949 ok = mscat_asn1_oid_equal(oid, CAT_NAME_VALUE_OBJID);
950 if (ok) {
951 char *name;
952 uint32_t flags;
953 char *value;
954 int cmp;
956 rc = ctl_parse_name_value(ctl,
957 tmp_ctx,
958 &content,
959 &name,
960 &flags,
961 &value);
962 if (rc != 0) {
963 goto done;
966 DBG_DEBUG("Parsed NameValue: name=%s, flags=%u, value=%s",
967 name,
968 flags,
969 value);
971 cmp = strcmp(name, "File");
972 if (cmp == 0) {
973 m->file.name = talloc_move(m, &value);
974 m->file.flags = flags;
976 continue;
979 cmp = strcmp(name, "OSAttr");
980 if (cmp == 0) {
981 m->osattr.value = talloc_move(m, &value);
982 m->osattr.flags = flags;
984 continue;
988 ok = mscat_asn1_oid_equal(oid, CAT_MEMBERINFO_OBJID);
989 if (ok) {
990 char *name;
991 uint32_t id;
993 rc = ctl_parse_member_info(ctl,
994 tmp_ctx,
995 &content,
996 &name,
997 &id);
998 if (rc != 0) {
999 goto done;
1002 m->info.guid = talloc_move(m, &name);
1003 m->info.id = id;
1005 continue;
1008 ok = mscat_asn1_oid_equal(oid, SPC_INDIRECT_DATA_OBJID);
1009 if (ok) {
1010 rc = ctl_spc_indirect_data(ctl,
1012 &content,
1013 &m->mac.type,
1014 &m->mac.digest,
1015 &m->mac.digest_size);
1016 if (rc != 0) {
1017 goto done;
1020 continue;
1024 rc = 0;
1025 done:
1026 talloc_free(tmp_ctx);
1027 return rc;
1030 int mscat_ctl_get_member(struct mscat_ctl *ctl,
1031 TALLOC_CTX *mem_ctx,
1032 unsigned int idx,
1033 struct mscat_ctl_member **pmember)
1035 TALLOC_CTX *tmp_ctx;
1036 struct mscat_ctl_member *m = NULL;
1037 int rc = -1;
1039 tmp_ctx = talloc_new(mem_ctx);
1040 if (tmp_ctx == NULL) {
1041 return -1;
1044 m = talloc_zero(tmp_ctx, struct mscat_ctl_member);
1045 if (m == NULL) {
1046 rc = -1;
1047 goto done;
1050 if (ctl->version == 1) {
1051 m->checksum.type = MSCAT_CHECKSUM_STRING;
1052 rc = ctl_get_member_checksum_string(ctl,
1054 idx,
1055 &m->checksum.string,
1056 &m->checksum.size);
1057 } else if (ctl->version == 2) {
1058 m->checksum.type = MSCAT_CHECKSUM_BLOB;
1059 rc = ctl_get_member_checksum_blob(ctl,
1061 idx,
1062 &m->checksum.blob,
1063 &m->checksum.size);
1065 if (rc != 0) {
1066 goto done;
1069 rc = ctl_get_member_attributes(ctl,
1070 mem_ctx,
1071 idx,
1073 if (rc != 0) {
1074 goto done;
1077 *pmember = talloc_move(mem_ctx, &m);
1079 rc = 0;
1080 done:
1081 talloc_free(tmp_ctx);
1082 return rc;
1085 int mscat_ctl_get_member_count(struct mscat_ctl *ctl)
1087 int count = 0;
1088 int rc;
1090 rc = asn1_number_of_elements(ctl->tree_ctl,
1091 "members",
1092 &count);
1093 if (rc != ASN1_SUCCESS) {
1094 return -1;
1097 return count;
1100 int mscat_ctl_get_attribute(struct mscat_ctl *ctl,
1101 TALLOC_CTX *mem_ctx,
1102 unsigned int idx,
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;
1109 char *name = NULL;
1110 uint32_t flags = 0;
1111 char *value = NULL;
1112 struct mscat_ctl_attribute *a = NULL;
1113 DATA_BLOB encapsulated_data_blob = data_blob_null;
1114 int rc;
1116 tmp_ctx = talloc_new(mem_ctx);
1117 if (tmp_ctx == NULL) {
1118 return -1;
1121 a = talloc_zero(tmp_ctx, struct mscat_ctl_attribute);
1122 if (a == NULL) {
1123 rc = -1;
1124 goto done;
1127 el1 = talloc_asprintf(tmp_ctx,
1128 "attributes.?%u.dataId",
1129 idx);
1130 if (el1 == NULL) {
1131 rc = -1;
1132 goto done;
1135 oid = mscat_asn1_get_oid(tmp_ctx,
1136 ctl->tree_ctl,
1137 el1);
1138 if (oid == NULL) {
1139 rc = -1;
1140 goto done;
1143 el2 = talloc_asprintf(tmp_ctx,
1144 "attributes.?%u.encapsulated_data",
1145 idx);
1146 if (el2 == NULL) {
1147 rc = -1;
1148 goto done;
1151 rc = mscat_asn1_read_value(tmp_ctx,
1152 ctl->tree_ctl,
1153 el2,
1154 &encapsulated_data_blob);
1155 if (rc != ASN1_SUCCESS) {
1156 goto done;
1159 rc = ctl_parse_name_value(ctl,
1160 tmp_ctx,
1161 &encapsulated_data_blob,
1162 &name,
1163 &flags,
1164 &value);
1165 if (rc != 0) {
1166 goto done;
1169 a->name = talloc_move(a, &name);
1170 a->flags = flags;
1171 a->value = talloc_move(a, &value);
1173 *pattribute = talloc_move(mem_ctx, &a);
1175 rc = 0;
1176 done:
1177 talloc_free(tmp_ctx);
1178 return rc;
1181 int mscat_ctl_get_attribute_count(struct mscat_ctl *ctl)
1183 int count = 0;
1184 int rc;
1186 rc = asn1_number_of_elements(ctl->tree_ctl,
1187 "attributes",
1188 &count);
1189 if (rc != ASN1_SUCCESS) {
1190 return -1;
1193 return count;