Fixed and documented example.c
[deb_shairplay.git] / src / lib / rsapem.c
1 /**
2 * Copyright (C) 2011-2012 Juho Vähä-Herttua
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 */
14
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <ctype.h>
19
20 #include "rsapem.h"
21 #include "base64.h"
22
23 #define RSAPRIVHEADER "-----BEGIN RSA PRIVATE KEY-----"
24 #define RSAPRIVFOOTER "-----END RSA PRIVATE KEY-----"
25
26 struct rsapem_s {
27 unsigned char *data;
28 unsigned int datalen;
29 unsigned int datapos;
30 };
31
32 rsapem_t *
33 rsapem_init(const char *pemstr)
34 {
35 rsapem_t *rsapem=NULL;
36 const char *header;
37 const char *footer;
38 base64_t *b64dec;
39 unsigned char *data;
40 int datalen;
41
42 header = strstr(pemstr, RSAPRIVHEADER);
43 footer = strstr(pemstr, RSAPRIVFOOTER);
44 if (!header || !footer) {
45 return NULL;
46 }
47
48
49 /* Base64 decode the whole input excluding header and footer */
50 b64dec = base64_init(NULL, 0, 1);
51 datalen = base64_decode(b64dec, &data, pemstr+sizeof(RSAPRIVHEADER),
52 (footer-header)-sizeof(RSAPRIVHEADER));
53 base64_destroy(b64dec);
54 b64dec = NULL;
55
56 if (datalen < 0) {
57 return NULL;
58 }
59
60 #ifdef RSAPEM_DEBUG
61 {
62 int i;
63 printf("Decoded output:\n");
64 for (i=0; i<datalen; i++) {
65 printf("%02x", data[i]);
66 }
67 printf("\n");
68 }
69 #endif
70
71 /* Check that first 4 bytes are all valid */
72 if (datalen < 4 || data[0] != 0x30 || data[1] != 0x82) {
73 free(data);
74 return NULL;
75 } else if (((data[2] << 8) | data[3]) != datalen-4) {
76 free(data);
77 return NULL;
78 }
79
80 rsapem = calloc(1, sizeof(rsapem_t));
81 if (!rsapem) {
82 free(data);
83 return NULL;
84 }
85
86 /* Initialize the data */
87 rsapem->data = data;
88 rsapem->datalen = datalen;
89 rsapem->datapos = 4;
90
91 data = NULL;
92 datalen = rsapem_read_vector(rsapem, &data);
93 if (datalen != 1 && data[0] != 0x00) {
94 free(data);
95 rsapem_destroy(rsapem);
96 return NULL;
97 }
98 free(data);
99 return rsapem;
100 }
101
102 void
103 rsapem_destroy(rsapem_t *rsapem)
104 {
105 if (rsapem) {
106 free(rsapem->data);
107 free(rsapem);
108 }
109 }
110
111 int
112 rsapem_read_vector(rsapem_t *rsapem, unsigned char **data)
113 {
114 unsigned int length;
115 unsigned char *ptr;
116
117 if (rsapem->datalen-rsapem->datapos < 2) {
118 return -1;
119 }
120 if (rsapem->data[rsapem->datapos] != 0x02) {
121 return -2;
122 }
123
124 /* Read vector length */
125 length = rsapem->data[rsapem->datapos+1];
126 if (length <= 0x80) {
127 rsapem->datapos += 2;
128 } else if (length == 0x81) {
129 if (rsapem->datalen-rsapem->datapos < 3) {
130 return -3;
131 }
132 length = rsapem->data[rsapem->datapos+2];
133 rsapem->datapos += 3;
134 } else if (length == 0x82) {
135 if (rsapem->datalen-rsapem->datapos < 4) {
136 return -3;
137 }
138 length = (rsapem->data[rsapem->datapos+2] << 8) |
139 rsapem->data[rsapem->datapos+3];
140 rsapem->datapos += 4;
141 } else {
142 return -3;
143 }
144
145 /* Check that we have enough data available */
146 if (rsapem->datalen-rsapem->datapos < length) {
147 return -4;
148 }
149
150 /* Allocate data buffer and read bytes */
151 ptr = malloc(length);
152 if (!ptr) {
153 return -5;
154 }
155 memcpy(ptr, rsapem->data+rsapem->datapos, length);
156 rsapem->datapos += length;
157
158 /* Return buffer and length */
159 *data = ptr;
160 return length;
161 }
162