]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 | 1 | /* |
d8f41ccd | 2 | * Copyright (c) 2003-2006,2008-2013 Apple Inc. All Rights Reserved. |
b1ab9ed8 A |
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 | * SecAsn1Coder.h: ANS1 encode/decode object, ANSI C version. | |
24 | */ | |
25 | ||
26 | #include "SecAsn1Coder.h" | |
27 | #include "plarenas.h" | |
28 | #include "prerror.h" | |
29 | #include "seccomon.h" | |
30 | #include "secasn1.h" | |
427c49bc | 31 | #include <Security/SecBase.h> |
b1ab9ed8 A |
32 | |
33 | /* | |
34 | * Default chunk size for new arena pool. | |
35 | * FIXME: analyze & measure different defaults here. I'm pretty sure | |
36 | * that only performance - not correct behavior - is affected by | |
37 | * an arena pool's chunk size. | |
38 | */ | |
39 | #define CHUNKSIZE_DEF 1024 | |
40 | ||
41 | /* | |
42 | * Caller's SecAsn1CoderRef points to one of these. | |
43 | */ | |
44 | typedef struct SecAsn1Coder { | |
45 | PLArenaPool *mPool; | |
46 | } SecAsn1Coder_t; | |
47 | ||
48 | /* | |
49 | * Create/destroy SecAsn1Coder object. | |
50 | */ | |
51 | OSStatus SecAsn1CoderCreate( | |
52 | SecAsn1CoderRef *coder) | |
53 | { | |
54 | if(coder == NULL) { | |
427c49bc | 55 | return errSecParam; |
b1ab9ed8 A |
56 | } |
57 | SecAsn1CoderRef _coder = (SecAsn1CoderRef)malloc(sizeof(SecAsn1Coder_t)); | |
58 | _coder->mPool = PORT_NewArena(CHUNKSIZE_DEF); | |
59 | if(_coder->mPool == NULL) { | |
427c49bc A |
60 | free(_coder); |
61 | return errSecAllocate; | |
b1ab9ed8 A |
62 | } |
63 | *coder = _coder; | |
427c49bc | 64 | return errSecSuccess; |
b1ab9ed8 A |
65 | } |
66 | ||
67 | OSStatus SecAsn1CoderRelease( | |
68 | SecAsn1CoderRef coder) | |
69 | { | |
70 | if(coder == NULL) { | |
427c49bc | 71 | return errSecParam; |
b1ab9ed8 A |
72 | } |
73 | if(coder->mPool != NULL) { | |
74 | /* | |
75 | * Note: we're asking for a memory zero here, but | |
76 | * PORT_FreeArena doesn't do that (yet). | |
77 | */ | |
78 | PORT_FreeArena(coder->mPool, PR_TRUE); | |
79 | coder->mPool = NULL; | |
80 | } | |
81 | free(coder); | |
427c49bc | 82 | return errSecSuccess; |
b1ab9ed8 A |
83 | } |
84 | ||
85 | /* | |
86 | * DER decode an untyped item per the specified template array. | |
87 | * The result is allocated in this SecAsn1Coder's memory pool and | |
88 | * is freed when this object is released. | |
89 | * | |
90 | * The dest pointer is a template-specific struct allocated by the caller | |
91 | * and must be zeroed by the caller. | |
92 | */ | |
93 | OSStatus SecAsn1Decode( | |
94 | SecAsn1CoderRef coder, | |
95 | const void *src, // DER-encoded source | |
96 | size_t len, | |
97 | const SecAsn1Template *templ, | |
98 | void *dest) | |
99 | { | |
100 | if((coder == NULL) || (src == NULL) || (templ == NULL) || (dest == NULL)) { | |
427c49bc | 101 | return errSecParam; |
b1ab9ed8 A |
102 | } |
103 | SECStatus prtn = SEC_ASN1Decode(coder->mPool, dest, templ, (const char *)src, len); | |
104 | if(prtn) { | |
105 | return errSecDecode; | |
106 | } | |
107 | else { | |
427c49bc | 108 | return errSecSuccess; |
b1ab9ed8 A |
109 | } |
110 | } | |
111 | ||
112 | /* | |
113 | * Convenience routine, decode from a SecAsn1Item. | |
114 | */ | |
115 | OSStatus SecAsn1DecodeData( | |
116 | SecAsn1CoderRef coder, | |
117 | const SecAsn1Item *src, | |
118 | const SecAsn1Template *templ, | |
119 | void *dest) | |
120 | { | |
121 | return SecAsn1Decode(coder, src->Data, src->Length, templ, dest); | |
122 | } | |
123 | ||
124 | /* | |
125 | * DER encode. The encoded data (in dest.Data) is allocated in this | |
126 | * SecAsn1Coder's memory pool and is freed when this object is released. | |
127 | * | |
128 | * The src pointer is a template-specific struct. | |
129 | */ | |
130 | OSStatus SecAsn1EncodeItem( | |
131 | SecAsn1CoderRef coder, | |
132 | const void *src, | |
133 | const SecAsn1Template *templ, | |
134 | SecAsn1Item *dest) | |
135 | { | |
136 | if((coder == NULL) || (src == NULL) || (templ == NULL) || (dest == NULL)) { | |
427c49bc | 137 | return errSecParam; |
b1ab9ed8 A |
138 | } |
139 | dest->Data = NULL; | |
140 | dest->Length = 0; | |
141 | ||
142 | SecAsn1Item *rtnItem = SEC_ASN1EncodeItem(coder->mPool, dest, src, templ); | |
143 | if(rtnItem == NULL) { | |
144 | /* FIXME what to return here? */ | |
427c49bc | 145 | return errSecParam; |
b1ab9ed8 A |
146 | } |
147 | else { | |
427c49bc | 148 | return errSecSuccess; |
b1ab9ed8 A |
149 | } |
150 | } | |
151 | ||
152 | /* | |
153 | * Some alloc-related methods which come in handy when using | |
154 | * this object. All memory is allocated using this object's | |
155 | * memory pool. Caller never has to free it. Used for | |
156 | * temp allocs of memory which only needs a scope which is the | |
157 | * same as this object. | |
158 | * | |
427c49bc | 159 | * These return a errSecAllocate in the highly unlikely event of |
b1ab9ed8 A |
160 | * a malloc failure. |
161 | */ | |
162 | void *SecAsn1Malloc( | |
163 | SecAsn1CoderRef coder, | |
164 | size_t len) | |
165 | { | |
5c19dc3a A |
166 | #pragma clang diagnostic push |
167 | #pragma clang diagnostic ignored "-Wnonnull" | |
168 | // After introducing nullability annotations, coder is supposed to be nonnull, suppress the warning | |
b1ab9ed8 A |
169 | if(coder == NULL) { |
170 | return NULL; | |
171 | } | |
5c19dc3a | 172 | #pragma clang diagnostic pop |
b1ab9ed8 A |
173 | return PORT_ArenaAlloc(coder->mPool, len); |
174 | } | |
175 | ||
176 | /* malloc item.Data, set item.Length */ | |
177 | OSStatus SecAsn1AllocItem( | |
178 | SecAsn1CoderRef coder, | |
179 | SecAsn1Item *item, | |
180 | size_t len) | |
181 | { | |
182 | if((coder == NULL) || (item == NULL)) { | |
427c49bc | 183 | return errSecParam; |
b1ab9ed8 A |
184 | } |
185 | item->Data = (uint8_t *)PORT_ArenaAlloc(coder->mPool, len); | |
186 | if(item->Data == NULL) { | |
427c49bc | 187 | return errSecAllocate; |
b1ab9ed8 A |
188 | } |
189 | item->Length = len; | |
427c49bc | 190 | return errSecSuccess; |
b1ab9ed8 A |
191 | } |
192 | ||
193 | /* malloc and copy, various forms */ | |
194 | OSStatus SecAsn1AllocCopy( | |
195 | SecAsn1CoderRef coder, | |
196 | const void *src, | |
197 | size_t len, | |
198 | SecAsn1Item *dest) | |
199 | { | |
200 | if(src == NULL) { | |
427c49bc | 201 | return errSecParam; |
b1ab9ed8 A |
202 | } |
203 | OSStatus ortn = SecAsn1AllocItem(coder, dest, len); | |
204 | if(ortn) { | |
205 | return ortn; | |
206 | } | |
207 | memmove(dest->Data, src, len); | |
427c49bc | 208 | return errSecSuccess; |
b1ab9ed8 A |
209 | } |
210 | ||
211 | OSStatus SecAsn1AllocCopyItem( | |
212 | SecAsn1CoderRef coder, | |
213 | const SecAsn1Item *src, | |
214 | SecAsn1Item *dest) | |
215 | { | |
216 | return SecAsn1AllocCopy(coder, src->Data, src->Length, dest); | |
217 | } | |
218 | ||
219 | bool SecAsn1OidCompare(const SecAsn1Oid *oid1, const SecAsn1Oid *oid2) { | |
220 | if (!oid1 || !oid2) | |
221 | return oid1 == oid2; | |
222 | if (oid1->Length != oid2->Length) | |
223 | return false; | |
224 | return !memcmp(oid1->Data, oid2->Data, oid1->Length); | |
225 | } |