1/* 2 * Copyright (c) 2003,2011-2012,2014 Apple Inc. All Rights Reserved. 3 * 4 * The contents of this file constitute Original Code as defined in and are 5 * subject to the Apple Public Source License Version 1.2 (the 'License'). 6 * You may not use this file except in compliance with the License. Please 7 * obtain a copy of the License at http://www.apple.com/publicsource and 8 * read it before using this file. 9 * 10 * This Original Code and all software distributed under the License are 11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 12 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 13 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 14 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 15 * Please see the License for the specific language governing rights and 16 * limitations under the License. 17 */ 18 19/* 20 File: cuPem.h 21 22 Description: PEM encode/decode routines 23 24 Author: dmitch 25 26*/ 27 28#include "cuPem.h" 29#include <stdlib.h> 30#include <stdio.h> 31#include <strings.h> 32#include <ctype.h> 33#include "cuEnc64.h" 34 35#define PEM_SCAN_LEN 8192 36 37/* 38 * Determine if specified blob appears to be PEM format. 39 * Returns 1 if so, 0 if not. 40 */ 41int isPem( 42 const unsigned char *inData, 43 unsigned inDataLen) 44{ 45 /* 46 * 1. The entire blob must be printable ASCII. 47 */ 48 const unsigned char *cp = inData; 49 for(unsigned dex=0; dex<inDataLen; dex++, cp++) { 50 if(!isprint(*cp) && !isspace(*cp)) { 51 return 0; 52 } 53 } 54 55 /* 56 * Search for "-----BEGIN " and "-----END". 57 * No strnstr() on X, so copy and NULL terminate to use strstr. 58 * First, get the first PEM_SCAN_LEN chars or inDataLen, whichever 59 * is less. 60 */ 61 unsigned char buf[PEM_SCAN_LEN + 1]; 62 unsigned len = inDataLen; 63 if(len > PEM_SCAN_LEN) { 64 len = PEM_SCAN_LEN; 65 } 66 memcpy(buf, inData, len); 67 buf[len] = '\0'; 68 const char *p = strstr((const char *)buf, "-----BEGIN "); 69 if(p == NULL) { 70 return 0; 71 } 72 73 /* 74 * Now the last PEM_SCAN_LEN chars or inDataLen, whichever is less. 75 */ 76 if(inDataLen > PEM_SCAN_LEN) { 77 memcpy(buf, inData + inDataLen - PEM_SCAN_LEN, PEM_SCAN_LEN); 78 buf[PEM_SCAN_LEN] = '\0'; 79 } 80 /* else we already have whole blob in buf[] */ 81 p = strstr((const char *)buf, "-----END "); 82 if(p == NULL) { 83 return 0; 84 } 85 /* success */ 86 return 1; 87} 88 89int pemEncode( 90 const unsigned char *inData, 91 unsigned inDataLen, 92 unsigned char **outData, 93 unsigned *outDataLen, 94 const char *headerString) 95{ 96 unsigned char *enc; 97 unsigned encLen; 98 99 /* First base64 encode */ 100 enc = cuEnc64WithLines(inData, inDataLen, 64, &encLen); 101 if(enc == NULL) { 102 /* malloc error is actually the only known failure */ 103 printf("***pemEncode: Error encoding file. Aborting.\n"); 104 return -1; 105 } 106 107 /* estimate outsize - just be sloppy, way conservative */ 108 size_t outSize = encLen + (2 * strlen(headerString)) + 200; 109 *outData = (unsigned char *)malloc(outSize); 110 sprintf((char *)*outData, "-----BEGIN %s-----\n%s-----END %s-----\n", 111 headerString, (char *)enc, headerString); 112 *outDataLen = (unsigned int)strlen((char *)*outData); 113 114 if((*outData)[*outDataLen - 1] == '\0') { 115 (*outDataLen)--; 116 } 117 free(enc); 118 return 0; 119} 120 121int pemDecode( 122 const unsigned char *inData, 123 unsigned inDataLen, 124 unsigned char **outData, 125 unsigned *outDataLen) 126{ 127 char *cp; 128 char *curr1, *curr2; 129 char *startPem = NULL; 130 char *endPem = NULL; 131 unsigned char *out; 132 unsigned outLen; 133 int ourRtn = 0; 134 char *freeCp = NULL; 135 136 /* make the whole thing a NULL-terminated string */ 137 if(inData[inDataLen - 1] != '\0') { 138 cp = freeCp = (char *)malloc(inDataLen + 1); 139 memmove(cp, inData, inDataLen); 140 cp[inDataLen] = '\0'; 141 inDataLen++; 142 } 143 else { 144 /* already is */ 145 cp = (char *)inData; 146 } 147 148 /* cp is start of NULL-terminated buffer, size inDataLen */ 149 /* skip over everything until "-----" */ 150 curr1 = strstr(cp, "-----"); 151 if(curr1 == NULL) { 152 printf("***pemDecode: no terminator found\n"); 153 ourRtn = -1; 154 goto abort; 155 } 156 157 /* find end of separator line, handling both flavors of terminator */ 158 cp = curr1; 159 curr1 = strchr(cp, '\n'); 160 curr2 = strchr(cp, '\r'); 161 if((curr1 == NULL) & (curr2 == NULL)) { 162 printf("***pemDecode: Bad PEM format (1)\n"); 163 ourRtn = -1; 164 goto abort; 165 } 166 if(curr1 == NULL) { 167 startPem = curr2; 168 } 169 else { 170 startPem = curr1; 171 } 172 173 /* startPem points to end of separator line */ 174 /* locate ending terminator and lop it off */ 175 curr1 = strstr(startPem, "-----"); 176 if(curr1 == NULL) { 177 printf("***pemDecode: Bad PEM format (2)\n"); 178 ourRtn = -1; 179 goto abort; 180 } 181 endPem = curr1; 182 /* endPem points to last PEM data plus one */ 183 184 out = cuDec64((unsigned char *)startPem, (unsigned int)(endPem-startPem), &outLen); 185 if(out == NULL) { 186 printf("Bad PEM format (3)\n"); 187 ourRtn = -1; 188 goto abort; 189 } 190 *outData = out; 191 *outDataLen = outLen; 192abort: 193 if(freeCp) { 194 free(freeCp); 195 } 196 return ourRtn; 197} 198 199