lib: Add support to parse MS Catalog files
[samba.git] / lib / mscat / mscat_ctl.c
1 /*
2  * Copyright (c) 2016      Andreas Schneider <asn@samba.org>
3  *
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.
8  *
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.
13  *
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/>.
16  */
17
18 #include <errno.h>
19 #include <string.h>
20 #include <stdint.h>
21
22 #include <util/debug.h>
23 #include <util/byteorder.h>
24 #include <util/data_blob.h>
25 #include <charset.h>
26
27 #include "mscat.h"
28 #include "mscat_private.h"
29
30 #define ASN1_NULL_DATA "\x05\x00"
31 #define ASN1_NULL_DATA_SIZE 2
32
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"
36
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"
39
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"
43
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"
46
47 extern const asn1_static_node mscat_asn1_tab[];
48
49 struct mscat_ctl {
50         int version;
51         ASN1_TYPE asn1_desc;
52         ASN1_TYPE tree_ctl;
53         gnutls_datum_t raw_ctl;
54 };
55
56 static char *mscat_asn1_get_oid(TALLOC_CTX *mem_ctx,
57                                 asn1_node root,
58                                 const char *oid_name)
59 {
60         char oid_str[32] = {0};
61         int oid_len = sizeof(oid_str);
62         int rc;
63
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;
73         }
74
75         return talloc_strndup(mem_ctx, oid_str, oid_len);
76 }
77
78 static bool mscat_asn1_oid_equal(const char *o1, const char *o2)
79 {
80         int cmp;
81
82         cmp = strcmp(o1, o2);
83         if (cmp != 0) {
84                 return false;
85         }
86
87         return true;
88 }
89
90 static int mscat_asn1_read_value(TALLOC_CTX *mem_ctx,
91                                  asn1_node root,
92                                  const char *name,
93                                  DATA_BLOB *blob)
94 {
95         DATA_BLOB tmp = data_blob_null;
96         unsigned int etype = ASN1_ETYPE_INVALID;
97         int len = 0;
98         int rc;
99
100         rc = asn1_read_value_type(root, name, NULL, &len, &etype);
101         if (rc != ASN1_SUCCESS) {
102                 return rc;
103         }
104
105         if (etype == ASN1_ETYPE_BIT_STRING) {
106                 if (len + 7 < len) {
107                         return -1;
108                 }
109                 len = (len + 7) / 8;
110         }
111
112         if (len == 0) {
113                 *blob = data_blob_null;
114                 return 0;
115         }
116
117         if (len + 1 < len) {
118                 return -1;
119         }
120         tmp = data_blob_talloc_zero(mem_ctx, len + 1);
121         if (tmp.data == NULL) {
122                 return -1;
123         }
124
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;
132         }
133
134         if (etype == ASN1_ETYPE_BIT_STRING) {
135                 if (len + 7 < len) {
136                         return -1;
137                 }
138                 len = (len + 7) / 8;
139         }
140         tmp.length = len;
141
142         *blob = tmp;
143
144         return 0;
145 }
146
147 static int mscat_ctl_cleanup(struct mscat_ctl *ctl)
148 {
149         if (ctl->asn1_desc != ASN1_TYPE_EMPTY) {
150                 asn1_delete_structure(&ctl->asn1_desc);
151         }
152
153         return 0;
154 }
155
156 struct mscat_ctl *mscat_ctl_init(TALLOC_CTX *mem_ctx)
157 {
158         char error_string[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = {0};
159         struct mscat_ctl *cat_ctl = NULL;
160         int rc;
161
162         cat_ctl = talloc_zero(mem_ctx, struct mscat_ctl);
163         if (cat_ctl == NULL) {
164                 return NULL;
165         }
166         talloc_set_destructor(cat_ctl, mscat_ctl_cleanup);
167
168         cat_ctl->asn1_desc = ASN1_TYPE_EMPTY;
169         cat_ctl->tree_ctl = ASN1_TYPE_EMPTY;
170
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;
180         }
181
182         return cat_ctl;
183 }
184
185 int mscat_ctl_import(struct mscat_ctl *ctl,
186                      struct mscat_pkcs7 *pkcs7)
187 {
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;
193
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;
201         }
202
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;
210         }
211
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;
221         }
222
223         tmp_ctx = talloc_new(ctl);
224         if (tmp_ctx == NULL) {
225                 return -1;
226         }
227
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;
234         }
235
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;
242         }
243         talloc_free(oid);
244
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;
251         }
252
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;
266                 }
267         }
268
269         rc = 0;
270 done:
271         talloc_free(tmp_ctx);
272         return rc;
273 }
274
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)
280 {
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;
288
289         tmp_ctx = talloc_new(mem_ctx);
290         if (tmp_ctx == NULL) {
291                 return -1;
292         }
293
294         element = talloc_asprintf(tmp_ctx,
295                                   "members.?%u.checksum",
296                                   idx);
297         if (element == NULL) {
298                 goto done;
299         }
300
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;
308         }
309
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;
320         }
321
322         *pchecksum_size = strlen(checksum) + 1;
323         *pchecksum = talloc_move(mem_ctx, &checksum);
324
325         rc = 0;
326 done:
327         talloc_free(tmp_ctx);
328         return rc;
329 }
330
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)
336 {
337         TALLOC_CTX *tmp_ctx;
338         DATA_BLOB chksum = data_blob_null;
339         char *element = NULL;
340         int rc = -1;
341
342         tmp_ctx = talloc_new(mem_ctx);
343         if (tmp_ctx == NULL) {
344                 return -1;
345         }
346
347         element = talloc_asprintf(tmp_ctx,
348                                   "members.?%u.checksum",
349                                   idx);
350         if (element == NULL) {
351                 goto done;
352         }
353
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;
361         }
362
363         *pchecksum = talloc_move(mem_ctx, &chksum.data);
364         *pchecksum_size = chksum.length;
365
366         rc = 0;
367 done:
368         talloc_free(tmp_ctx);
369         return rc;
370 }
371
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)
378 {
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;
388
389         tmp_ctx = talloc_new(mem_ctx);
390         if (tmp_ctx == NULL) {
391                 return -1;
392         }
393
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;
402         }
403
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;
413         }
414
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;
423         }
424
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;
433         }
434
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;
443         }
444
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;
455         }
456
457         *pflags = RIVAL(flags_blob.data, 0);
458
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;
469         }
470
471         rc = 0;
472 done:
473         talloc_free(tmp_ctx);
474         return rc;
475 }
476
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)
482 {
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;
491
492         tmp_ctx = talloc_new(mem_ctx);
493         if (tmp_ctx == NULL) {
494                 return -1;
495         }
496
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;
505         }
506
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;
516         }
517
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;
526         }
527
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;
536         }
537
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;
548         }
549
550         *pid = RSVAL(id_blob.data, 0);
551
552         rc = 0;
553 done:
554         talloc_free(tmp_ctx);
555         return rc;
556 }
557
558
559 static int ctl_spc_pe_image_data(struct mscat_ctl *ctl,
560                                  TALLOC_CTX *mem_ctx,
561                                  DATA_BLOB *content,
562                                  char **pfile)
563 {
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;
572
573         tmp_ctx = talloc_new(mem_ctx);
574         if (tmp_ctx == NULL) {
575                 return -1;
576         }
577
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;
586         }
587
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;
597         }
598
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);
605
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;
612         }
613
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;
622         }
623
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");
629         }
630
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");
636         }
637
638         cmp = strncmp((char *)choice_blob.data, "file", choice_blob.length);
639         if (cmp == 0) {
640                 DATA_BLOB file_blob;
641                 char *link;
642
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;
649                 }
650
651                 link = talloc_asprintf(tmp_ctx, "link.file.%s", (char *)choice_blob.data);
652                 if (link == NULL) {
653                         rc = -1;
654                         goto done;
655                 }
656
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;
667                 }
668
669                 cmp = strncmp((char *)choice_blob.data, "unicode", choice_blob.length);
670                 if (cmp == 0) {
671                         size_t converted_size = 0;
672                         bool ok;
673
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;
684                         }
685                 }
686
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;
695                         }
696                 }
697         }
698
699         if (file != NULL) {
700                 *pfile = talloc_move(mem_ctx, &file);
701         }
702
703         rc = 0;
704 done:
705         talloc_free(tmp_ctx);
706         return rc;
707 }
708
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)
715 {
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;
726
727         tmp_ctx = talloc_new(mem_ctx);
728         if (tmp_ctx == NULL) {
729                 return -1;
730         }
731
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;
740         }
741
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;
751         }
752
753         oid = mscat_asn1_get_oid(tmp_ctx,
754                                  spc_indirect_data,
755                                  "data.type");
756         if (oid == NULL) {
757                 goto done;
758         }
759
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;
768         }
769
770         ok = mscat_asn1_oid_equal(oid, SPC_PE_IMAGE_DATA_OBJID);
771         if (ok) {
772                 char *file = NULL;
773
774                 rc = ctl_spc_pe_image_data(ctl,
775                                            tmp_ctx,
776                                            &data_value_blob,
777                                            &file);
778                 if (rc != 0) {
779                         goto done;
780                 }
781
782                 /* Just returns <<<Obsolete>>> as file */
783                 DBG_NOTICE(">>> LINK: %s",
784                            file);
785         }
786
787         oid = mscat_asn1_get_oid(tmp_ctx,
788                                  spc_indirect_data,
789                                  "messageDigest.digestAlgorithm.algorithm");
790         if (oid == NULL) {
791                 goto done;
792         }
793
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;
801
802                 if (digest_parameters_blob.length != ASN1_NULL_DATA_SIZE) {
803                         rc = -1;
804                         goto done;
805                 }
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;
812                 }
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;
817         }
818
819         ok = mscat_asn1_oid_equal(oid, HASH_SHA1_OBJID);
820         if (ok) {
821                 mac_algorithm = MSCAT_MAC_SHA1;
822         }
823
824         ok = mscat_asn1_oid_equal(oid, HASH_SHA256_OBJID);
825         if (ok) {
826                 mac_algorithm = MSCAT_MAC_SHA256;
827         }
828
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;
840                 }
841         }
842
843         *pmac_algorithm = mac_algorithm;
844         *pdigest = talloc_move(mem_ctx, &digest_blob.data);
845         *pdigest_size = digest_blob.length;
846
847         rc = 0;
848 done:
849         talloc_free(tmp_ctx);
850         return rc;
851 }
852
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)
857 {
858         TALLOC_CTX *tmp_ctx;
859         char *el1 = NULL;
860         int count = 0;
861         int i;
862         int rc = -1;
863
864         tmp_ctx = talloc_new(mem_ctx);
865         if (tmp_ctx == NULL) {
866                 return -1;
867         }
868
869         el1 = talloc_asprintf(tmp_ctx,
870                               "members.?%u.attributes",
871                               idx);
872         if (el1 == NULL) {
873                 goto done;
874         }
875
876         rc = asn1_number_of_elements(ctl->tree_ctl,
877                                      el1,
878                                      &count);
879         if (rc != ASN1_SUCCESS) {
880                 goto done;
881         }
882
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;
891
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;
899                 }
900
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;
908                 }
909
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;
918                 }
919
920                 DBG_DEBUG("Decode element (startEnd)  %s",
921                           el2);
922
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;
931                 }
932                 if (content_start < content_end) {
933                         goto done;
934                 }
935                 content_len = content_end - content_start + 1;
936
937                 DBG_DEBUG("Content data_blob length: %zu",
938                           content_len);
939
940                 content = data_blob_talloc_zero(tmp_ctx, content_len);
941                 if (content.data == NULL) {
942                         rc = -1;
943                         goto done;
944                 }
945                 memcpy(content.data,
946                        &ctl->raw_ctl.data[content_start],
947                        content_len);
948
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;
955
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;
964                         }
965
966                         DBG_DEBUG("Parsed NameValue: name=%s, flags=%u, value=%s",
967                                   name,
968                                   flags,
969                                   value);
970
971                         cmp = strcmp(name, "File");
972                         if (cmp == 0) {
973                                 m->file.name = talloc_move(m, &value);
974                                 m->file.flags = flags;
975
976                                 continue;
977                         }
978
979                         cmp = strcmp(name, "OSAttr");
980                         if (cmp == 0) {
981                                 m->osattr.value = talloc_move(m, &value);
982                                 m->osattr.flags = flags;
983
984                                 continue;
985                         }
986                 }
987
988                 ok = mscat_asn1_oid_equal(oid, CAT_MEMBERINFO_OBJID);
989                 if (ok) {
990                         char *name;
991                         uint32_t id;
992
993                         rc = ctl_parse_member_info(ctl,
994                                                    tmp_ctx,
995                                                    &content,
996                                                    &name,
997                                                    &id);
998                         if (rc != 0) {
999                                 goto done;
1000                         }
1001
1002                         m->info.guid = talloc_move(m, &name);
1003                         m->info.id = id;
1004
1005                         continue;
1006                 }
1007
1008                 ok = mscat_asn1_oid_equal(oid, SPC_INDIRECT_DATA_OBJID);
1009                 if (ok) {
1010                         rc = ctl_spc_indirect_data(ctl,
1011                                                   m,
1012                                                   &content,
1013                                                   &m->mac.type,
1014                                                   &m->mac.digest,
1015                                                   &m->mac.digest_size);
1016                         if (rc != 0) {
1017                                 goto done;
1018                         }
1019
1020                         continue;
1021                 }
1022         }
1023
1024         rc = 0;
1025 done:
1026         talloc_free(tmp_ctx);
1027         return rc;
1028 }
1029
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)
1034 {
1035         TALLOC_CTX *tmp_ctx;
1036         struct mscat_ctl_member *m = NULL;
1037         int rc = -1;
1038
1039         tmp_ctx = talloc_new(mem_ctx);
1040         if (tmp_ctx == NULL) {
1041                 return -1;
1042         }
1043
1044         m = talloc_zero(tmp_ctx, struct mscat_ctl_member);
1045         if (m == NULL) {
1046                 rc = -1;
1047                 goto done;
1048         }
1049
1050         if (ctl->version == 1) {
1051                 m->checksum.type = MSCAT_CHECKSUM_STRING;
1052                 rc = ctl_get_member_checksum_string(ctl,
1053                                                     m,
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,
1060                                                   m,
1061                                                   idx,
1062                                                   &m->checksum.blob,
1063                                                   &m->checksum.size);
1064         }
1065         if (rc != 0) {
1066                 goto done;
1067         }
1068
1069         rc = ctl_get_member_attributes(ctl,
1070                                        mem_ctx,
1071                                        idx,
1072                                        m);
1073         if (rc != 0) {
1074                 goto done;
1075         }
1076
1077         *pmember = talloc_move(mem_ctx, &m);
1078
1079         rc = 0;
1080 done:
1081         talloc_free(tmp_ctx);
1082         return rc;
1083 }
1084
1085 int mscat_ctl_get_member_count(struct mscat_ctl *ctl)
1086 {
1087         int count = 0;
1088         int rc;
1089
1090         rc = asn1_number_of_elements(ctl->tree_ctl,
1091                                      "members",
1092                                      &count);
1093         if (rc != ASN1_SUCCESS) {
1094                 return -1;
1095         }
1096
1097         return count;
1098 }
1099
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)
1104 {
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;
1115
1116         tmp_ctx = talloc_new(mem_ctx);
1117         if (tmp_ctx == NULL) {
1118                 return -1;
1119         }
1120
1121         a = talloc_zero(tmp_ctx, struct mscat_ctl_attribute);
1122         if (a == NULL) {
1123                 rc = -1;
1124                 goto done;
1125         }
1126
1127         el1 = talloc_asprintf(tmp_ctx,
1128                                   "attributes.?%u.dataId",
1129                                   idx);
1130         if (el1 == NULL) {
1131                 rc = -1;
1132                 goto done;
1133         }
1134
1135         oid = mscat_asn1_get_oid(tmp_ctx,
1136                                  ctl->tree_ctl,
1137                                  el1);
1138         if (oid == NULL) {
1139                 rc = -1;
1140                 goto done;
1141         }
1142
1143         el2 = talloc_asprintf(tmp_ctx,
1144                                   "attributes.?%u.encapsulated_data",
1145                                   idx);
1146         if (el2 == NULL) {
1147                 rc = -1;
1148                 goto done;
1149         }
1150
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;
1157         }
1158
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;
1167         }
1168
1169         a->name = talloc_move(a, &name);
1170         a->flags = flags;
1171         a->value = talloc_move(a, &value);
1172
1173         *pattribute = talloc_move(mem_ctx, &a);
1174
1175         rc = 0;
1176 done:
1177         talloc_free(tmp_ctx);
1178         return rc;
1179 }
1180
1181 int mscat_ctl_get_attribute_count(struct mscat_ctl *ctl)
1182 {
1183         int count = 0;
1184         int rc;
1185
1186         rc = asn1_number_of_elements(ctl->tree_ctl,
1187                                      "attributes",
1188                                      &count);
1189         if (rc != ASN1_SUCCESS) {
1190                 return -1;
1191         }
1192
1193         return count;
1194 }