1/*
2 * Copyright (c) 2009,2012,2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25#include "DER_Ticket.h"
26
27#include <libDER/asn1Types.h>
28#include <libDER/DER_Decode.h>
29#include <libDER/DER_Encode.h>
30#include <libDER/DER_Keys.h>
31
32/* Application Processor Ticket */
33const DERItemSpec DERApTicketItemSpecs[] =
34{
35	{ DER_OFFSET(DERApTicket, signatureAlgorithm),
36			ASN1_CONSTR_SEQUENCE,
37			DER_DEC_NO_OPTS | DER_ENC_WRITE_DER },
38	{ DER_OFFSET(DERApTicket, body),
39			ASN1_CONSTR_SET,
40			DER_DEC_NO_OPTS | DER_DEC_SAVE_DER | DER_ENC_WRITE_DER },
41	{ DER_OFFSET(DERApTicket, signature),
42			ASN1_OCTET_STRING,
43			DER_DEC_NO_OPTS },
44	{ DER_OFFSET(DERApTicket, certificates),
45			ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 1,
46			DER_DEC_NO_OPTS | DER_ENC_WRITE_DER }
47};
48const DERSize DERNumApTicketItemSpecs =
49	sizeof(DERApTicketItemSpecs) / sizeof(DERItemSpec);
50
51/* Baseband Ticket */
52const DERItemSpec DERBbTicketItemSpecs[] =
53{
54	{ DER_OFFSET(DERBbTicket, signatureAlgorithm),
55			ASN1_CONSTR_SEQUENCE,
56			DER_DEC_NO_OPTS | DER_ENC_WRITE_DER },
57	{ DER_OFFSET(DERBbTicket, body),
58			ASN1_CONSTR_SET,
59			DER_DEC_NO_OPTS | DER_DEC_SAVE_DER | DER_ENC_WRITE_DER },
60	{ DER_OFFSET(DERBbTicket, signature),
61			ASN1_OCTET_STRING,
62			DER_DEC_NO_OPTS },
63	{ DER_OFFSET(DERBbTicket, gpuk),
64			ASN1_CONTEXT_SPECIFIC | 2,
65			DER_DEC_NO_OPTS }
66};
67const DERSize DERNumBbTicketItemSpecs =
68	sizeof(DERBbTicketItemSpecs) / sizeof(DERItemSpec);
69
70#if 0
71/* We need to verify this value and use it here. */
72const DERByte rsaWithSha1Algorithm[] = {
73    0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05
74};
75#endif
76
77#ifdef FAST_SET_LOOKUP
78/* Iterates over all the tags in the set to build an index returned in
79   derSet. */
80DERReturn DERDecodeSetContentInit(
81	const DERItem   *content,			/* data to decode */
82	DERSet          *derSet)            /* IN/OUT, to use in DERDecodeSetTag */
83{
84    DERReturn drtn;
85    DERSequence derSeq;
86    memset(derSet->byTag, 0, derSet->capacity);
87    drtn = DERDecodeSeqContentInit(content, &derSeq);
88    if (drtn == DR_Success) {
89        DERDecodedInfo element;
90        while ((drtn = DERDecodeSeqNext(&derSeq, &element)) == DR_Success) {
91            if (element.tag >= derSet->capacity) return DR_UnexpectedTag;
92            derSet->byTag[element.tag] = element.content.data;
93        }
94        if (drtn == DR_EndOfSequence) drtn = DR_Success;
95    }
96    derSet->end = content->data + content->length;
97
98    return drtn;
99}
100
101DERReturn DERDecodeSetTag(
102	DERSet          *derSet,		/* data to decode */
103	DERTag			tag,			/* tag in sequence/set we are looking for. */
104	DERItem         *content)		/* RETURNED */
105{
106    DERReturn drtn;
107    DERTag tagNumber = tag & ASN1_TAGNUM_MASK;
108    if (tagNumber > derSet->capacity)
109        return DR_UnexpectedTag;
110    DERByte *start = derSet->byTag[tagNumber];
111    if (!start) return DR_UnexpectedTag;
112    DERItem derItem = { .data = start, .length = derSet->end - start };
113    DERDecodedInfo element;
114    drtn = DERDecodeItem(&derItem, &element);
115    if (drtn) return drtn;
116    if (tag != element.tag) return DR_UnexpectedTag;
117    *content = element.content;
118
119    return drtn;
120}
121#endif /* FAST_SET_LOOKUP */
122
123/* Returns the item with tag from the sequence or set pointed to by der.
124   result DR_EndOfSequence if the tag was not found. */
125DERReturn DERSetDecodeItemWithTag(
126	const DERItem	*der,			/* data to decode */
127	DERTag			tag,			/* tag in sequence/set we are looking for. */
128	DERItem         *content)		/* RETURNED */
129{
130    DERReturn drtn;
131    DERSequence derSeq;
132    DERTag topTag;
133    drtn = DERDecodeSeqInit(der, &topTag, &derSeq);
134    if (drtn == DR_Success) {
135        DERDecodedInfo info;
136        while ((drtn = DERDecodeSeqNext(&derSeq, &info)) == DR_Success) {
137            if (info.tag == tag) {
138                *content = info.content;
139                return DR_Success;
140            }
141        }
142    }
143
144    return drtn;
145}
146
147DERReturn DERDecodeApTicket(
148	const DERItem	*contents,
149	DERApTicket		*ticket,            /* RETURNED */
150	DERSize			*numUsedBytes)      /* RETURNED */
151{
152    DERReturn drtn;
153    DERDecodedInfo decodedTicket;
154    drtn = DERDecodeItem(contents, &decodedTicket);
155    if (drtn != DR_Success) goto badTicket;
156    drtn = DERParseSequenceContent(&decodedTicket.content,
157        DERNumApTicketItemSpecs, DERApTicketItemSpecs, ticket, 0);
158    if (drtn != DR_Success) goto badTicket;
159
160    /* Decode the algorithm sequence. */
161    DERAlgorithmId algorithm = {};
162    drtn = DERParseSequenceContent(&ticket->signatureAlgorithm,
163        DERNumAlgorithmIdItemSpecs, DERAlgorithmIdItemSpecs, &algorithm, 0);
164    if (drtn != DR_Success) goto badTicket;
165    /* TODO Check algorithm oid and ensure there are no params.
166       Alternatively replace the code above with a simple memcmp with
167       an already ASN.1 encoded algorithm parms block. */
168
169badTicket:
170    *numUsedBytes = decodedTicket.content.length +
171        decodedTicket.content.data - contents->data;
172
173    return drtn;
174}
175
176DERReturn DERDecodeBbTicket(
177	const DERItem	*contents,
178	DERBbTicket		*ticket,            /* RETURNED */
179	DERSize			*numUsedBytes)      /* RETURNED */
180{
181    DERReturn drtn;
182    DERDecodedInfo decodedTicket;
183    drtn = DERDecodeItem(contents, &decodedTicket);
184    if (drtn != DR_Success) goto badTicket;
185    drtn = DERParseSequenceContent(&decodedTicket.content,
186        DERNumBbTicketItemSpecs, DERBbTicketItemSpecs, ticket, 0);
187    if (drtn != DR_Success) goto badTicket;
188
189    /* Decode the algorithm sequence. */
190    DERAlgorithmId algorithm = {};
191    drtn = DERParseSequenceContent(&ticket->signatureAlgorithm,
192        DERNumAlgorithmIdItemSpecs, DERAlgorithmIdItemSpecs, &algorithm, 0);
193    if (drtn != DR_Success) goto badTicket;
194    /* TODO Check algorithm oid and ensure there are no params.
195       Alternatively replace the code above with a simple memcmp with
196       an already ASN.1 encoded algorithm parms block. */
197
198badTicket:
199    *numUsedBytes = decodedTicket.content.length +
200        decodedTicket.content.data - contents->data;
201
202    return drtn;
203}
204