1/*
2 * Copyright (c) 2005-2008,2010-2011,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/*
26 * DER_Digest.h - DER encode a DigestInfo
27 *
28 */
29
30#include <libDER/DER_Digest.h>
31
32/*
33 * Create an encoded DigestInfo based on the specified SHA1 digest.
34 * The digest must be 20 bytes long.
35 *
36 * Result is placed in caller's buffer, which must be at least of
37 * length DER_DIGEST_INFO_LEN bytes.
38 *
39 * The *resultLen parameter is the available size in the result
40 * buffer on input, and the actual length of the encoded DigestInfo
41 * on output.
42 *
43 * In the interest of saving code space, this just drops the caller's
44 * digest into an otherwise hard-coded, fixed, encoded SHA1 DigestInfo.
45 * Nothing is variable so we know the whole thing. It looks like this:
46 *
47 * SEQUENCE OF <33> {
48 *		SEQUENCE OF <9> {
49 *			OID <5>: OID : < 06 05 2B 0E 03 02 1A >
50 *			NULL
51 *		}
52 *		OCTET STRING <20>:
53 *			55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55
54 *			55 55 55 55
55 *		}
56 *
57 *
58 * tower.local:digestInfo> hexdump -x /tmp/encodedDigest
59 * 0000000    3021    3009    0605    2b0e    0302    1a05    0004    1455
60 * 0000010    5555    5555    5555    5555    5555    5555    5555    5555
61 * *
62 * 0000020
63 */
64
65static const unsigned char encodedSha1Digest[] =
66{
67	0x30, 0x21,				/* top level sequence length 33 */
68		  0x30, 0x09,		/* algorithm ID, sequence length 9 */
69			    0x06, 0x05,	/* alg OID, length 5, SHA1 */
70					  0x2b, 0x0e, 0x03, 0x02, 0x1a,
71				0x05, 0x00,	/* NULL parameters */
72		  0x04, 0x14		/* integer length 20 */
73							/* digest follows */
74};
75
76DERReturn DEREncodeSHA1DigestInfo(
77	const DERByte	*sha1Digest,
78	DERSize			sha1DigestLen,
79	DERByte			*result,		/* encoded result RETURNED here */
80	DERSize			*resultLen)		/* IN/OUT */
81{
82	DERSize totalLen = sizeof(encodedSha1Digest) + DER_SHA1_DIGEST_LEN;
83
84	if((sha1Digest == NULL) || (sha1DigestLen != DER_SHA1_DIGEST_LEN) ||
85		(result == NULL) || (resultLen == NULL)) {
86		return DR_ParamErr;
87	}
88	if(*resultLen < DER_SHA1_DIGEST_INFO_LEN) {
89		return DR_BufOverflow;
90	}
91	DERMemmove(result, encodedSha1Digest, sizeof(encodedSha1Digest));
92	DERMemmove(result + sizeof(encodedSha1Digest), sha1Digest, DER_SHA1_DIGEST_LEN);
93	*resultLen = totalLen;
94	return DR_Success;
95}
96
97/*
98        joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101)
99        csor(3) nistalgorithm(4) hashAlgs(2) sha256(1)
100
101        future ones to add: sha384(2)  sha512(3)  sha224(4)
102*/
103static const unsigned char encodedSha256Digest[] =
104{
105	0x30, 0x31,				/* top level sequence length 49 */
106		  0x30, 0x0d,		/* algorithm ID, sequence length 13 */
107                0x06, 0x09,
108                      0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
109                0x05, 0x00, /* NULL parameters */
110		  0x04, 0x20		/* integer length 32 */
111							/* digest follows */
112};
113
114DERReturn DEREncodeSHA256DigestInfo(
115	const DERByte	*sha256Digest,
116	DERSize			sha256DigestLen,
117	DERByte			*result,		/* encoded result RETURNED here */
118	DERSize			*resultLen)		/* IN/OUT */
119{
120	DERSize totalLen = sizeof(encodedSha256Digest) + DER_SHA256_DIGEST_LEN;
121
122	if((sha256Digest == NULL) || (sha256DigestLen != DER_SHA256_DIGEST_LEN) ||
123		(result == NULL) || (resultLen == NULL)) {
124		return DR_ParamErr;
125	}
126	if(*resultLen < DER_SHA256_DIGEST_INFO_LEN) {
127		return DR_BufOverflow;
128	}
129	DERMemmove(result, encodedSha256Digest, sizeof(encodedSha256Digest));
130	DERMemmove(result + sizeof(encodedSha256Digest), sha256Digest, DER_SHA256_DIGEST_LEN);
131	*resultLen = totalLen;
132	return DR_Success;
133}
134
135
136/* Same thing, MD5/MD2 */
137static const unsigned char encodedMdDigest[] =
138{
139	0x30, 0x20,				/* top level sequence length 32 */
140		  0x30, 0x0c,		/* algorithm ID, sequence length 12 */
141			    0x06, 0x08,	/* alg OID, length 8, MD2/MD5 */
142					  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02,
143							0x05,	/* 5 = MD5, 2 = MD2 */
144				0x05, 0x00,	/* NULL parameters */
145		  0x04, 0x10		/* integer length 16 */
146							/* digest follows */
147};
148
149#define WHICH_DIGEST_INDEX	13
150#define WHICH_DIGEST_MD2	2
151#define WHICH_DIGEST_MD5	5
152
153DERReturn DEREncodeMDDigestInfo(
154	WhichDigest		whichDigest,
155	const DERByte	*mdDigest,
156	DERSize			mdDigestLen,
157	DERByte			*result,		/* encoded result RETURNED here */
158	DERSize			*resultLen)		/* IN/OUT */
159{
160	DERSize totalLen = sizeof(encodedMdDigest) + DER_MD_DIGEST_LEN;
161
162	if((mdDigest == NULL) || (mdDigestLen != DER_MD_DIGEST_LEN) ||
163		(result == NULL) || (resultLen == NULL)) {
164		return DR_ParamErr;
165	}
166	if(*resultLen < totalLen) {
167		return DR_BufOverflow;
168	}
169	DERMemmove(result, encodedMdDigest, sizeof(encodedMdDigest));
170	DERMemmove(result + sizeof(encodedMdDigest), mdDigest, DER_MD_DIGEST_LEN);
171	switch(whichDigest) {
172		case WD_MD2:
173			result[WHICH_DIGEST_INDEX] = WHICH_DIGEST_MD2;
174			break;
175		case WD_MD5:
176			result[WHICH_DIGEST_INDEX] = WHICH_DIGEST_MD5;
177			break;
178		default:
179			return DR_ParamErr;
180	}
181	*resultLen = totalLen;
182	return DR_Success;
183}
184