1/*
2 * Copyright (c) 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 * tsaDERUtilities.c -  ASN1 templates Time Stamping Authority requests and responses.
24 * see rfc3161.asn1 for ASN.1 and other comments
25 */
26
27#include <libDER/asn1Types.h>
28#include <libDER/DER_Decode.h>
29#include <AssertMacros.h>
30#include <Security/cssmtype.h>
31#include <stdlib.h>
32#include "tsaDERUtilities.h"
33
34#ifndef DER_MULTIBYTE_TAGS
35#error We expect DER_MULTIBYTE_TAGS
36#endif
37
38/* PKIStatusInfo */
39typedef struct {
40    DERItem     status;         // INTEGER
41	DERItem     statusString;      // UTF8_STRING | SEC_ASN1_OPTIONAL
42    DERItem     failInfo;          // BIT_STRING | SEC_ASN1_OPTIONAL
43} DERPKIStatusInfo;
44
45/* xx */
46typedef struct {
47	DERItem     statusString;      // UTF8_STRING | SEC_ASN1_OPTIONAL
48} DERPKIStatusStringInner;
49
50/* TimeStampResp */
51typedef struct
52{
53    DERItem status;             /* PKIStatusInfo */
54    DERItem timeStampToken;     /* TimeStampToken */
55} DERTimeStampResp;
56
57/* TimeStampResp */
58const DERItemSpec DERTimeStampRespItemSpecs[] =
59{
60    { DER_OFFSET(DERTimeStampResp, status),
61        ASN1_CONSTR_SEQUENCE, DER_DEC_NO_OPTS },
62    { DER_OFFSET(DERTimeStampResp, timeStampToken),
63        ASN1_CONSTR_SEQUENCE, DER_DEC_NO_OPTS | DER_DEC_OPTIONAL | DER_DEC_SAVE_DER}
64};
65const DERSize DERNumTimeStampRespItemSpecs = sizeof(DERTimeStampRespItemSpecs) / sizeof(DERItemSpec);
66
67/*
68    This code is here rather than in libsecurity_smime because
69    libsecurity_smime doesn't know about libDER
70*/
71
72int DERDecodeTimeStampResponse(
73	const CSSM_DATA *contents,
74    CSSM_DATA *derStatus,
75    CSSM_DATA *derTimeStampToken,
76	size_t			*numUsedBytes)      /* RETURNED */
77{
78    DERReturn drtn = DR_ParamErr;
79    DERDecodedInfo decodedPackage;
80
81    if (contents)
82    {
83        DERItem derContents = {.data = contents->Data, .length = contents->Length };
84        DERTimeStampResp derResponse = {{0,},{0,}};
85        DERReturn rx;
86        require_noerr(DERDecodeItem(&derContents, &decodedPackage), badResponse);
87
88        rx = DERParseSequenceContent(&decodedPackage.content,
89            DERNumTimeStampRespItemSpecs, DERTimeStampRespItemSpecs,
90            &derResponse, 0);
91        if (rx != DR_Success)
92            goto badResponse;
93/*
94        require_noerr(DERParseSequenceContent(&decodedPackage.content,
95            DERNumTimeStampRespItemSpecs, DERTimeStampRespItemSpecs,
96            &derResponse, 0), badResponse);
97*/
98        if (derStatus && derResponse.status.data)
99        {
100            derStatus->Data = malloc(derResponse.status.length);
101            derStatus->Length = derResponse.status.length;
102            memcpy(derStatus->Data, derResponse.status.data, derStatus->Length);
103        }
104        if (derTimeStampToken && derResponse.timeStampToken.data)
105        {
106            derTimeStampToken->Data = malloc(derResponse.timeStampToken.length);
107            derTimeStampToken->Length = derResponse.timeStampToken.length;
108            memcpy(derTimeStampToken->Data, derResponse.timeStampToken.data, derTimeStampToken->Length);
109        }
110    }
111
112    drtn = DR_Success;
113
114badResponse:
115    if (numUsedBytes)
116        *numUsedBytes = decodedPackage.content.length +
117            decodedPackage.content.data - contents->Data;
118
119    return drtn;
120}
121
122