1/* 2 * Copyright (c) 2003-2006,2008-2010 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 * 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" 31#include <Security/SecBase.h> 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 */ 44typedef struct SecAsn1Coder { 45 PLArenaPool *mPool; 46} SecAsn1Coder_t; 47 48/* 49 * Create/destroy SecAsn1Coder object. 50 */ 51OSStatus SecAsn1CoderCreate( 52 SecAsn1CoderRef *coder) 53{ 54 if(coder == NULL) { 55 return errSecParam; 56 } 57 SecAsn1CoderRef _coder = (SecAsn1CoderRef)malloc(sizeof(SecAsn1Coder_t)); 58 _coder->mPool = PORT_NewArena(CHUNKSIZE_DEF); 59 if(_coder->mPool == NULL) { 60 free(_coder); 61 return errSecAllocate; 62 } 63 *coder = _coder; 64 return errSecSuccess; 65} 66 67OSStatus SecAsn1CoderRelease( 68 SecAsn1CoderRef coder) 69{ 70 if(coder == NULL) { 71 return errSecParam; 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); 82 return errSecSuccess; 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 */ 93OSStatus 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)) { 101 return errSecParam; 102 } 103 SECStatus prtn = SEC_ASN1Decode(coder->mPool, dest, templ, (const char *)src, len); 104 if(prtn) { 105 return errSecDecode; 106 } 107 else { 108 return errSecSuccess; 109 } 110} 111 112/* 113 * Convenience routine, decode from a SecAsn1Item. 114 */ 115OSStatus 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 */ 130OSStatus 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)) { 137 return errSecParam; 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? */ 145 return errSecParam; 146 } 147 else { 148 return errSecSuccess; 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 * 159 * These return a errSecAllocate in the highly unlikely event of 160 * a malloc failure. 161 */ 162void *SecAsn1Malloc( 163 SecAsn1CoderRef coder, 164 size_t len) 165{ 166 if(coder == NULL) { 167 return NULL; 168 } 169 return PORT_ArenaAlloc(coder->mPool, len); 170} 171 172/* malloc item.Data, set item.Length */ 173OSStatus SecAsn1AllocItem( 174 SecAsn1CoderRef coder, 175 SecAsn1Item *item, 176 size_t len) 177{ 178 if((coder == NULL) || (item == NULL)) { 179 return errSecParam; 180 } 181 item->Data = (uint8_t *)PORT_ArenaAlloc(coder->mPool, len); 182 if(item->Data == NULL) { 183 return errSecAllocate; 184 } 185 item->Length = len; 186 return errSecSuccess; 187} 188 189/* malloc and copy, various forms */ 190OSStatus SecAsn1AllocCopy( 191 SecAsn1CoderRef coder, 192 const void *src, 193 size_t len, 194 SecAsn1Item *dest) 195{ 196 if(src == NULL) { 197 return errSecParam; 198 } 199 OSStatus ortn = SecAsn1AllocItem(coder, dest, len); 200 if(ortn) { 201 return ortn; 202 } 203 memmove(dest->Data, src, len); 204 return errSecSuccess; 205} 206 207OSStatus SecAsn1AllocCopyItem( 208 SecAsn1CoderRef coder, 209 const SecAsn1Item *src, 210 SecAsn1Item *dest) 211{ 212 return SecAsn1AllocCopy(coder, src->Data, src->Length, dest); 213} 214 215bool SecAsn1OidCompare(const SecAsn1Oid *oid1, const SecAsn1Oid *oid2) { 216 if (!oid1 || !oid2) 217 return oid1 == oid2; 218 if (oid1->Length != oid2->Length) 219 return false; 220 return !memcmp(oid1->Data, oid2->Data, oid1->Length); 221} 222