lib:mscat: Use size_t for len value to fix build issue
[vlendec/samba-autobuild/.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 tmp_len = 0;
98         size_t len;
99         int rc;
100
101         rc = asn1_read_value_type(root, name, NULL, &tmp_len, &etype);
102         if (rc != ASN1_SUCCESS) {
103                 return rc;
104         }
105         len = tmp_len;
106
107         if (etype == ASN1_ETYPE_BIT_STRING) {
108                 if (len + 7 < len) {
109                         return -1;
110                 }
111                 len = (len + 7) / 8;
112         }
113
114         if (len == 0) {
115                 *blob = data_blob_null;
116                 return 0;
117         }
118
119         if (len + 1 < len) {
120                 return -1;
121         }
122         tmp = data_blob_talloc_zero(mem_ctx, len + 1);
123         if (tmp.data == NULL) {
124                 return -1;
125         }
126
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;
134         }
135         len = tmp_len;
136
137         if (etype == ASN1_ETYPE_BIT_STRING) {
138                 if (len + 7 < len) {
139                         return -1;
140                 }
141                 len = (len + 7) / 8;
142         }
143         tmp.length = len;
144
145         *blob = tmp;
146
147         return 0;
148 }
149
150 static int mscat_ctl_cleanup(struct mscat_ctl *ctl)
151 {
152         if (ctl->asn1_desc != ASN1_TYPE_EMPTY) {
153                 asn1_delete_structure(&ctl->asn1_desc);
154         }
155
156         return 0;
157 }
158
159 struct mscat_ctl *mscat_ctl_init(TALLOC_CTX *mem_ctx)
160 {
161         char error_string[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = {0};
162         struct mscat_ctl *cat_ctl = NULL;
163         int rc;
164
165         cat_ctl = talloc_zero(mem_ctx, struct mscat_ctl);
166         if (cat_ctl == NULL) {
167                 return NULL;
168         }
169         talloc_set_destructor(cat_ctl, mscat_ctl_cleanup);
170
171         cat_ctl->asn1_desc = ASN1_TYPE_EMPTY;
172         cat_ctl->tree_ctl = ASN1_TYPE_EMPTY;
173
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;
183         }
184
185         return cat_ctl;
186 }
187
188 int mscat_ctl_import(struct mscat_ctl *ctl,
189                      struct mscat_pkcs7 *pkcs7)
190 {
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;
196
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;
204         }
205
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;
213         }
214
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;
224         }
225
226         tmp_ctx = talloc_new(ctl);
227         if (tmp_ctx == NULL) {
228                 return -1;
229         }
230
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;
237         }
238
239         ok = mscat_asn1_oid_equal(oid, CATALOG_LIST_OBJOID);
240         if (!ok) {
241                 DBG_ERR("Invalid oid (%s), expected CATALOG_LIST_OBJOID",
242                         oid);
243                 rc = -1;
244                 goto done;
245         }
246         talloc_free(oid);
247
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;
254         }
255
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",
266                                 oid);
267                         rc = -1;
268                         goto done;
269                 }
270         }
271
272         rc = 0;
273 done:
274         talloc_free(tmp_ctx);
275         return rc;
276 }
277
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)
283 {
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;
291
292         tmp_ctx = talloc_new(mem_ctx);
293         if (tmp_ctx == NULL) {
294                 return -1;
295         }
296
297         element = talloc_asprintf(tmp_ctx,
298                                   "members.?%u.checksum",
299                                   idx);
300         if (element == NULL) {
301                 goto done;
302         }
303
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;
311         }
312
313         ok = convert_string_talloc(mem_ctx,
314                                    CH_UTF16LE,
315                                    CH_UNIX,
316                                    chksum_ucs2.data,
317                                    chksum_ucs2.length,
318                                    (void **)&checksum,
319                                    &converted_size);
320         if (!ok) {
321                 rc = -1;
322                 goto done;
323         }
324
325         *pchecksum_size = strlen(checksum) + 1;
326         *pchecksum = talloc_move(mem_ctx, &checksum);
327
328         rc = 0;
329 done:
330         talloc_free(tmp_ctx);
331         return rc;
332 }
333
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)
339 {
340         TALLOC_CTX *tmp_ctx;
341         DATA_BLOB chksum = data_blob_null;
342         char *element = NULL;
343         int rc = -1;
344
345         tmp_ctx = talloc_new(mem_ctx);
346         if (tmp_ctx == NULL) {
347                 return -1;
348         }
349
350         element = talloc_asprintf(tmp_ctx,
351                                   "members.?%u.checksum",
352                                   idx);
353         if (element == NULL) {
354                 goto done;
355         }
356
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;
364         }
365
366         *pchecksum = talloc_move(mem_ctx, &chksum.data);
367         *pchecksum_size = chksum.length;
368
369         rc = 0;
370 done:
371         talloc_free(tmp_ctx);
372         return rc;
373 }
374
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)
381 {
382         char error_string[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = {0};
383         ASN1_TYPE name_value = ASN1_TYPE_EMPTY;
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;
391
392         tmp_ctx = talloc_new(mem_ctx);
393         if (tmp_ctx == NULL) {
394                 return -1;
395         }
396
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;
405         }
406
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",
413                         asn1_strerror(rc),
414                         error_string);
415                 goto done;
416         }
417
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;
426         }
427
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;
436         }
437
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;
446         }
447
448         ok = convert_string_talloc(mem_ctx,
449                                    CH_UTF16BE,
450                                    CH_UNIX,
451                                    name_blob.data,
452                                    name_blob.length,
453                                    (void **)pname,
454                                    &converted_size);
455         if (!ok) {
456                 rc = ASN1_MEM_ERROR;
457                 goto done;
458         }
459
460         *pflags = RIVAL(flags_blob.data, 0);
461
462         ok = convert_string_talloc(mem_ctx,
463                                    CH_UTF16LE,
464                                    CH_UNIX,
465                                    value_blob.data,
466                                    value_blob.length,
467                                    (void **)pvalue,
468                                    &converted_size);
469         if (!ok) {
470                 rc = ASN1_MEM_ERROR;
471                 goto done;
472         }
473
474         rc = 0;
475 done:
476         talloc_free(tmp_ctx);
477         return rc;
478 }
479
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)
485 {
486         char error_string[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = {0};
487         ASN1_TYPE member_info = ASN1_TYPE_EMPTY;
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;
494
495         tmp_ctx = talloc_new(mem_ctx);
496         if (tmp_ctx == NULL) {
497                 return -1;
498         }
499
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;
508         }
509
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",
516                         asn1_strerror(rc),
517                         error_string);
518                 goto done;
519         }
520
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;
529         }
530
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;
539         }
540
541         ok = convert_string_talloc(mem_ctx,
542                                    CH_UTF16BE,
543                                    CH_UNIX,
544                                    name_blob.data,
545                                    name_blob.length,
546                                    (void **)pname,
547                                    &converted_size);
548         if (!ok) {
549                 rc = ASN1_MEM_ERROR;
550                 goto done;
551         }
552
553         *pid = RSVAL(id_blob.data, 0);
554
555         rc = 0;
556 done:
557         talloc_free(tmp_ctx);
558         return rc;
559 }
560
561
562 static int ctl_spc_pe_image_data(struct mscat_ctl *ctl,
563                                  TALLOC_CTX *mem_ctx,
564                                  DATA_BLOB *content,
565                                  char **pfile)
566 {
567         char error_string[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = {0};
568         ASN1_TYPE spc_pe_image_data = ASN1_TYPE_EMPTY;
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;
575
576         tmp_ctx = talloc_new(mem_ctx);
577         if (tmp_ctx == NULL) {
578                 return -1;
579         }
580
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;
589         }
590
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",
597                         asn1_strerror(rc),
598                         error_string);
599                 goto done;
600         }
601
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);
608
609                 DBG_ERR(">>> SPC_PE_IMAGE_DATA FLAGS=0x%08x",
610                         flags);
611         } else  {
612                 DBG_ERR("Failed to parse 'flags' in CATALOG.SpcPEImageData - %s",
613                         asn1_strerror(rc));
614                 goto done;
615         }
616
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",
623                         asn1_strerror(rc));
624                 goto done;
625         }
626
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");
632         }
633
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");
639         }
640
641         cmp = strncmp((char *)choice_blob.data, "file", choice_blob.length);
642         if (cmp == 0) {
643                 DATA_BLOB file_blob;
644                 char *link;
645
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;
652                 }
653
654                 link = talloc_asprintf(tmp_ctx, "link.file.%s", (char *)choice_blob.data);
655                 if (link == NULL) {
656                         rc = -1;
657                         goto done;
658                 }
659
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",
666                                 link,
667                                 asn1_strerror(rc));
668                         rc = -1;
669                         goto done;
670                 }
671
672                 cmp = strncmp((char *)choice_blob.data, "unicode", choice_blob.length);
673                 if (cmp == 0) {
674                         size_t converted_size = 0;
675                         bool ok;
676
677                         ok = convert_string_talloc(tmp_ctx,
678                                                    CH_UTF16BE,
679                                                    CH_UNIX,
680                                                    file_blob.data,
681                                                    file_blob.length,
682                                                    (void **)&file,
683                                                    &converted_size);
684                         if (!ok) {
685                                 rc = -1;
686                                 goto done;
687                         }
688                 }
689
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;
698                         }
699                 }
700         }
701
702         if (file != NULL) {
703                 *pfile = talloc_move(mem_ctx, &file);
704         }
705
706         rc = 0;
707 done:
708         talloc_free(tmp_ctx);
709         return rc;
710 }
711
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)
718 {
719         char error_string[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = {0};
720         ASN1_TYPE spc_indirect_data = ASN1_TYPE_EMPTY;
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;
729
730         tmp_ctx = talloc_new(mem_ctx);
731         if (tmp_ctx == NULL) {
732                 return -1;
733         }
734
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;
743         }
744
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",
751                         asn1_strerror(rc),
752                         error_string);
753                 goto done;
754         }
755
756         oid = mscat_asn1_get_oid(tmp_ctx,
757                                  spc_indirect_data,
758                                  "data.type");
759         if (oid == NULL) {
760                 goto done;
761         }
762
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;
771         }
772
773         ok = mscat_asn1_oid_equal(oid, SPC_PE_IMAGE_DATA_OBJID);
774         if (ok) {
775                 char *file = NULL;
776
777                 rc = ctl_spc_pe_image_data(ctl,
778                                            tmp_ctx,
779                                            &data_value_blob,
780                                            &file);
781                 if (rc != 0) {
782                         goto done;
783                 }
784
785                 /* Just returns <<<Obsolete>>> as file */
786                 DBG_NOTICE(">>> LINK: %s",
787                            file);
788         }
789
790         oid = mscat_asn1_get_oid(tmp_ctx,
791                                  spc_indirect_data,
792                                  "messageDigest.digestAlgorithm.algorithm");
793         if (oid == NULL) {
794                 goto done;
795         }
796
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;
804
805                 if (digest_parameters_blob.length != ASN1_NULL_DATA_SIZE) {
806                         rc = -1;
807                         goto done;
808                 }
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;
815                 }
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;
820         }
821
822         ok = mscat_asn1_oid_equal(oid, HASH_SHA1_OBJID);
823         if (ok) {
824                 mac_algorithm = MSCAT_MAC_SHA1;
825         }
826
827         ok = mscat_asn1_oid_equal(oid, HASH_SHA256_OBJID);
828         if (ok) {
829                 mac_algorithm = MSCAT_MAC_SHA256;
830         }
831
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;
843                 }
844         }
845
846         *pmac_algorithm = mac_algorithm;
847         *pdigest = talloc_move(mem_ctx, &digest_blob.data);
848         *pdigest_size = digest_blob.length;
849
850         rc = 0;
851 done:
852         talloc_free(tmp_ctx);
853         return rc;
854 }
855
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)
860 {
861         TALLOC_CTX *tmp_ctx;
862         char *el1 = NULL;
863         int count = 0;
864         int i;
865         int rc = -1;
866
867         tmp_ctx = talloc_new(mem_ctx);
868         if (tmp_ctx == NULL) {
869                 return -1;
870         }
871
872         el1 = talloc_asprintf(tmp_ctx,
873                               "members.?%u.attributes",
874                               idx);
875         if (el1 == NULL) {
876                 goto done;
877         }
878
879         rc = asn1_number_of_elements(ctl->tree_ctl,
880                                      el1,
881                                      &count);
882         if (rc != ASN1_SUCCESS) {
883                 goto done;
884         }
885
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;
894
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;
902                 }
903
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;
911                 }
912
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;
921                 }
922
923                 DBG_DEBUG("Decode element (startEnd)  %s",
924                           el2);
925
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;
934                 }
935                 if (content_start < content_end) {
936                         goto done;
937                 }
938                 content_len = content_end - content_start + 1;
939
940                 DBG_DEBUG("Content data_blob length: %zu",
941                           content_len);
942
943                 content = data_blob_talloc_zero(tmp_ctx, content_len);
944                 if (content.data == NULL) {
945                         rc = -1;
946                         goto done;
947                 }
948                 memcpy(content.data,
949                        &ctl->raw_ctl.data[content_start],
950                        content_len);
951
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;
958
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;
967                         }
968
969                         DBG_DEBUG("Parsed NameValue: name=%s, flags=%u, value=%s",
970                                   name,
971                                   flags,
972                                   value);
973
974                         cmp = strcmp(name, "File");
975                         if (cmp == 0) {
976                                 m->file.name = talloc_move(m, &value);
977                                 m->file.flags = flags;
978
979                                 continue;
980                         }
981
982                         cmp = strcmp(name, "OSAttr");
983                         if (cmp == 0) {
984                                 m->osattr.value = talloc_move(m, &value);
985                                 m->osattr.flags = flags;
986
987                                 continue;
988                         }
989                 }
990
991                 ok = mscat_asn1_oid_equal(oid, CAT_MEMBERINFO_OBJID);
992                 if (ok) {
993                         char *name;
994                         uint32_t id;
995
996                         rc = ctl_parse_member_info(ctl,
997                                                    tmp_ctx,
998                                                    &content,
999                                                    &name,
1000                                                    &id);
1001                         if (rc != 0) {
1002                                 goto done;
1003                         }
1004
1005                         m->info.guid = talloc_move(m, &name);
1006                         m->info.id = id;
1007
1008                         continue;
1009                 }
1010
1011                 ok = mscat_asn1_oid_equal(oid, SPC_INDIRECT_DATA_OBJID);
1012                 if (ok) {
1013                         rc = ctl_spc_indirect_data(ctl,
1014                                                   m,
1015                                                   &content,
1016                                                   &m->mac.type,
1017                                                   &m->mac.digest,
1018                                                   &m->mac.digest_size);
1019                         if (rc != 0) {
1020                                 goto done;
1021                         }
1022
1023                         continue;
1024                 }
1025         }
1026
1027         rc = 0;
1028 done:
1029         talloc_free(tmp_ctx);
1030         return rc;
1031 }
1032
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)
1037 {
1038         TALLOC_CTX *tmp_ctx;
1039         struct mscat_ctl_member *m = NULL;
1040         int rc = -1;
1041
1042         tmp_ctx = talloc_new(mem_ctx);
1043         if (tmp_ctx == NULL) {
1044                 return -1;
1045         }
1046
1047         m = talloc_zero(tmp_ctx, struct mscat_ctl_member);
1048         if (m == NULL) {
1049                 rc = -1;
1050                 goto done;
1051         }
1052
1053         if (ctl->version == 1) {
1054                 m->checksum.type = MSCAT_CHECKSUM_STRING;
1055                 rc = ctl_get_member_checksum_string(ctl,
1056                                                     m,
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,
1063                                                   m,
1064                                                   idx,
1065                                                   &m->checksum.blob,
1066                                                   &m->checksum.size);
1067         }
1068         if (rc != 0) {
1069                 goto done;
1070         }
1071
1072         rc = ctl_get_member_attributes(ctl,
1073                                        mem_ctx,
1074                                        idx,
1075                                        m);
1076         if (rc != 0) {
1077                 goto done;
1078         }
1079
1080         *pmember = talloc_move(mem_ctx, &m);
1081
1082         rc = 0;
1083 done:
1084         talloc_free(tmp_ctx);
1085         return rc;
1086 }
1087
1088 int mscat_ctl_get_member_count(struct mscat_ctl *ctl)
1089 {
1090         int count = 0;
1091         int rc;
1092
1093         rc = asn1_number_of_elements(ctl->tree_ctl,
1094                                      "members",
1095                                      &count);
1096         if (rc != ASN1_SUCCESS) {
1097                 return -1;
1098         }
1099
1100         return count;
1101 }
1102
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)
1107 {
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;
1118
1119         tmp_ctx = talloc_new(mem_ctx);
1120         if (tmp_ctx == NULL) {
1121                 return -1;
1122         }
1123
1124         a = talloc_zero(tmp_ctx, struct mscat_ctl_attribute);
1125         if (a == NULL) {
1126                 rc = -1;
1127                 goto done;
1128         }
1129
1130         el1 = talloc_asprintf(tmp_ctx,
1131                                   "attributes.?%u.dataId",
1132                                   idx);
1133         if (el1 == NULL) {
1134                 rc = -1;
1135                 goto done;
1136         }
1137
1138         oid = mscat_asn1_get_oid(tmp_ctx,
1139                                  ctl->tree_ctl,
1140                                  el1);
1141         if (oid == NULL) {
1142                 rc = -1;
1143                 goto done;
1144         }
1145
1146         el2 = talloc_asprintf(tmp_ctx,
1147                                   "attributes.?%u.encapsulated_data",
1148                                   idx);
1149         if (el2 == NULL) {
1150                 rc = -1;
1151                 goto done;
1152         }
1153
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;
1160         }
1161
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;
1170         }
1171
1172         a->name = talloc_move(a, &name);
1173         a->flags = flags;
1174         a->value = talloc_move(a, &value);
1175
1176         *pattribute = talloc_move(mem_ctx, &a);
1177
1178         rc = 0;
1179 done:
1180         talloc_free(tmp_ctx);
1181         return rc;
1182 }
1183
1184 int mscat_ctl_get_attribute_count(struct mscat_ctl *ctl)
1185 {
1186         int count = 0;
1187         int rc;
1188
1189         rc = asn1_number_of_elements(ctl->tree_ctl,
1190                                      "attributes",
1191                                      &count);
1192         if (rc != ASN1_SUCCESS) {
1193                 return -1;
1194         }
1195
1196         return count;
1197 }