1/*
2 * Copyright (c) 2000-2004,2006,2011-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//
26// cssmdata.cpp -- Manager different CssmData types
27//
28#include <security_cdsa_utilities/cssmdata.h>
29#include <security_utilities/utilities.h>
30#include <cstring>
31#include <algorithm>
32
33
34namespace Security {
35
36
37//
38// Comparing raw CSSM_DATA things
39//
40bool operator == (const CSSM_DATA &d1, const CSSM_DATA &d2)
41{
42    if (&d1 == &d2)
43        return true;	// identical
44    if (d1.Length != d2.Length)
45        return false;	// can't be
46    if (d1.Data == d2.Data)
47        return true;	// points to same data
48    return !memcmp(d1.Data, d2.Data, d1.Length);
49}
50
51
52//
53// CssmData out of line members
54//
55string CssmData::toString() const
56{
57    return data() ?
58        string(reinterpret_cast<const char *>(data()), length())
59        :
60        string();
61}
62
63
64//
65// Conversion from/to hex digits.
66// This could be separate functions, or Rep templates, but we just hang
67// it onto generic CssmData.
68//
69string CssmData::toHex() const
70{
71	static const char digits[] = "0123456789abcdef";
72	string result;
73	unsigned char *p = Data;
74	for (uint32 n = 0; n < length(); n++) {
75		result.push_back(digits[p[n] >> 4]);
76		result.push_back(digits[p[n] & 0xf]);
77	}
78	return result;
79}
80
81static unsigned char hexValue(char c)
82{
83	static const char digits[] = "0123456789abcdef";
84	if (const char *p = strchr(digits, tolower(c)))
85		return p - digits;
86	else
87		return 0;
88}
89
90void CssmData::fromHex(const char *hexDigits)
91{
92	size_t bytes = strlen(hexDigits) / 2;	// (discards malformed odd end)
93	length(bytes);	// (will assert if we try to grow it)
94	for (size_t n = 0; n < bytes; n++) {
95		Data[n] = hexValue(hexDigits[2*n]) << 4 | hexValue(hexDigits[2*n+1]);
96	}
97}
98
99
100//
101// Conversion from/to OID strings.
102// These are not strict; invalid inputs are not necessarily flagged as errors.
103//
104static unsigned long getOid(const CssmData &data, unsigned int &pos)
105{
106	unsigned long q = 0;
107	do {
108		q = q * 128 + (data.byte(pos) & ~0x80);
109	} while (pos < data.length() && data.byte(pos++) & 0x80);
110	return q;
111}
112
113string CssmData::toOid() const
114{
115	if (length() == 0)
116		return "";
117
118	unsigned int pos = 0;
119
120	// first byte is composite (q1,q2)
121	char buffer[10];
122	unsigned long oid1 = getOid(*this, pos);
123	unsigned long q1 = min(oid1 / 40, 2ul);
124	snprintf(buffer, sizeof(buffer), "%lu.%lu", q1, oid1 - q1 * 40);
125	string s = buffer;
126
127	// now for the rest
128	while (pos < length()) {
129		char buffer[20];
130		snprintf(buffer, sizeof(buffer), ".%lu", getOid(*this, pos));
131		s += buffer;
132	}
133	return s;
134}
135
136static void putOid(CssmOwnedData &data, unsigned long id)
137{
138	unsigned char buffer[sizeof(unsigned long) * 2];	// * (8/7) + 1, conservative
139	unsigned char *p = buffer + sizeof(buffer);
140	do {
141		*--p = 0x80 | (id & 0x7F);		// last 7 bits, high bit set
142	} while ((id >>= 7) > 0);
143	buffer[sizeof(buffer) - 1] &= ~0x80;	// clear last high bit (end of number)
144	data.append(p, buffer + sizeof(buffer) - p); // append generated byte string
145}
146
147//
148// Convert OID string (1.2.3...) into CssmOid form.
149// Allocates the data, replacing current contents.
150// Will not process oid elements out of unsigned long range.
151//
152void CssmOwnedData::fromOid(const char *oid)
153{
154	this->length(0);		// make empty
155
156	// first two elements get combined in weird&wacky ways
157	unsigned long q1 = strtoul(oid, (char **)&oid, 10);
158	if (*oid++ != '.')
159		return;
160	unsigned long q2 = strtoul(oid, (char **)&oid, 10);
161	putOid(*this, 40 * q1 + q2);
162	while (oid[0] == '.') {
163		oid++;
164		putOid(*this, strtoul(oid, (char **)&oid, 10));
165	}
166}
167
168
169//
170// Managed data objects
171//
172CssmManagedData::~CssmManagedData()
173{ }
174
175
176//
177// CssmOwnedData
178//
179void CssmOwnedData::set(CssmManagedData &source)
180{
181    if (source.length() == 0) {					// source is empty
182        reset();								// so just clear old data
183    } else if (allocator == source.allocator) {	// compatible allocators
184        if (referent.data() == source.data()) {	// same data *and* we own it?!
185            assert(this == &source);			//  this better *be* me!
186        } else {								// different data
187            reset();							// give up our old data
188            referent = source.release();		// take over source's data
189        }
190    } else {									// different allocators
191        copy(source);							// make a copy with our allocator
192        source.reset();							// release source's data
193    }
194}
195
196
197//
198// CssmAutoData
199//
200CssmData CssmAutoData::release()
201{
202    CssmData result = mData;
203    mData.clear();
204    return result;
205}
206
207void CssmAutoData::reset()
208{
209    allocator.free(mData);
210    mData.clear();
211}
212
213
214//
215// CssmRemoteData
216//
217CssmData CssmRemoteData::release()
218{
219    iOwnTheData = false;
220    return referent;
221}
222
223void CssmRemoteData::reset()
224{
225    if (iOwnTheData)
226        allocator.free(referent);
227    referent.clear();
228}
229
230
231//
232// Date stuff
233//
234CssmDateData::CssmDateData(const CSSM_DATE &date)
235: CssmData(buffer, sizeof(buffer))
236{
237	memcpy(buffer, date.Year, 4);
238	memcpy(buffer + 4, date.Month, 2);
239	memcpy(buffer + 6, date.Day, 2);
240}
241
242
243CssmData& CssmOwnedData::get() const throw()
244{
245	return referent;
246}
247
248}	// end namespace Security
249