Consolidate base64 encode/decode routines.
[exim.git] / src / src / pdkim / pdkim-rsa.c
1 #include "pdkim-rsa.h"
2 #include <stdlib.h>
3 #include <string.h>
4 #include "polarssl/private-x509parse_c.h"
5
6 /* PDKIM code (not copied from polarssl) */
7 /*
8 * Parse a public RSA key
9
10 OpenSSL RSA public key ASN1 container
11 0:d=0 hl=3 l= 159 cons: SEQUENCE
12 3:d=1 hl=2 l= 13 cons: SEQUENCE
13 5:d=2 hl=2 l= 9 prim: OBJECT:rsaEncryption
14 16:d=2 hl=2 l= 0 prim: NULL
15 18:d=1 hl=3 l= 141 prim: BIT STRING:RSAPublicKey (below)
16
17 RSAPublicKey ASN1 container
18 0:d=0 hl=3 l= 137 cons: SEQUENCE
19 3:d=1 hl=3 l= 129 prim: INTEGER:Public modulus
20 135:d=1 hl=2 l= 3 prim: INTEGER:Public exponent
21 */
22
23 int rsa_parse_public_key( rsa_context *rsa, unsigned char *buf, int buflen )
24 {
25 unsigned char *p, *end;
26 int ret, len;
27
28 p = buf;
29 end = buf+buflen;
30
31 if( ( ret = asn1_get_tag( &p, end, &len,
32 ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) {
33 return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT | ret );
34 }
35
36 if( ( ret = asn1_get_tag( &p, end, &len,
37 ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) == 0 ) {
38 /* Skip over embedded rsaEncryption Object */
39 p+=len;
40
41 /* The RSAPublicKey ASN1 container is wrapped in a BIT STRING */
42 if( ( ret = asn1_get_tag( &p, end, &len,
43 ASN1_BIT_STRING ) ) != 0 ) {
44 return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT | ret );
45 }
46
47 /* Limit range to that BIT STRING */
48 end = p + len;
49 p++;
50
51 if( ( ret = asn1_get_tag( &p, end, &len,
52 ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) {
53 return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT | ret );
54 }
55 }
56
57 if ( ( ( ret = asn1_get_mpi( &p, end, &(rsa->N) ) ) == 0 ) &&
58 ( ( ret = asn1_get_mpi( &p, end, &(rsa->E) ) ) == 0 ) ) {
59 rsa->len = mpi_size( &rsa->N );
60 return 0;
61 }
62
63 return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT | ret );
64 }
65
66 /*
67 * Parse a private RSA key
68 */
69 int rsa_parse_key( rsa_context *rsa, unsigned char *buf, int buflen,
70 unsigned char *pwd, int pwdlen )
71 {
72 int ret, len, enc;
73 unsigned char *s1, *s2;
74 unsigned char *p, *end;
75
76 s1 = (unsigned char *) strstr( (char *) buf,
77 "-----BEGIN RSA PRIVATE KEY-----" );
78
79 if( s1 != NULL )
80 {
81 s2 = (unsigned char *) strstr( (char *) buf,
82 "-----END RSA PRIVATE KEY-----" );
83
84 if( s2 == NULL || s2 <= s1 )
85 return( POLARSSL_ERR_X509_KEY_INVALID_PEM );
86
87 s1 += 31;
88 if( *s1 == '\r' ) s1++;
89 if( *s1 == '\n' ) s1++;
90 else return( POLARSSL_ERR_X509_KEY_INVALID_PEM );
91
92 enc = 0;
93
94 if( memcmp( s1, "Proc-Type: 4,ENCRYPTED", 22 ) == 0 )
95 {
96 return( POLARSSL_ERR_X509_FEATURE_UNAVAILABLE );
97 }
98
99 len = 0;
100 {
101 extern unsigned char * string_copyn(const unsigned char *, int);
102 extern int b64decode(unsigned char *, unsigned char **);
103 #define POLARSSL_ERR_BASE64_INVALID_CHARACTER 0x0012
104
105 s1 = string_copyn(s1, s2-s1); /* need nul-terminated string */
106 if ((len = b64decode(s1, &buf)) < 0)
107 return POLARSSL_ERR_BASE64_INVALID_CHARACTER
108 | POLARSSL_ERR_X509_KEY_INVALID_PEM;
109 }
110
111 buflen = len;
112
113 if( enc != 0 )
114 {
115 return( POLARSSL_ERR_X509_FEATURE_UNAVAILABLE );
116 }
117 }
118
119 memset( rsa, 0, sizeof( rsa_context ) );
120
121 p = buf;
122 end = buf + buflen;
123
124 /*
125 * RSAPrivateKey ::= SEQUENCE {
126 * version Version,
127 * modulus INTEGER, -- n
128 * publicExponent INTEGER, -- e
129 * privateExponent INTEGER, -- d
130 * prime1 INTEGER, -- p
131 * prime2 INTEGER, -- q
132 * exponent1 INTEGER, -- d mod (p-1)
133 * exponent2 INTEGER, -- d mod (q-1)
134 * coefficient INTEGER, -- (inverse of q) mod p
135 * otherPrimeInfos OtherPrimeInfos OPTIONAL
136 * }
137 */
138 if( ( ret = asn1_get_tag( &p, end, &len,
139 ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
140 {
141 rsa_free( rsa );
142 return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT | ret );
143 }
144
145 end = p + len;
146
147 if( ( ret = asn1_get_int( &p, end, &rsa->ver ) ) != 0 )
148 {
149 rsa_free( rsa );
150 return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT | ret );
151 }
152
153 if( rsa->ver != 0 )
154 {
155 rsa_free( rsa );
156 return( ret | POLARSSL_ERR_X509_KEY_INVALID_VERSION );
157 }
158
159 if( ( ret = asn1_get_mpi( &p, end, &rsa->N ) ) != 0 ||
160 ( ret = asn1_get_mpi( &p, end, &rsa->E ) ) != 0 ||
161 ( ret = asn1_get_mpi( &p, end, &rsa->D ) ) != 0 ||
162 ( ret = asn1_get_mpi( &p, end, &rsa->P ) ) != 0 ||
163 ( ret = asn1_get_mpi( &p, end, &rsa->Q ) ) != 0 ||
164 ( ret = asn1_get_mpi( &p, end, &rsa->DP ) ) != 0 ||
165 ( ret = asn1_get_mpi( &p, end, &rsa->DQ ) ) != 0 ||
166 ( ret = asn1_get_mpi( &p, end, &rsa->QP ) ) != 0 )
167 {
168 rsa_free( rsa );
169 return( ret | POLARSSL_ERR_X509_KEY_INVALID_FORMAT );
170 }
171
172 rsa->len = mpi_size( &rsa->N );
173
174 if( p != end )
175 {
176 rsa_free( rsa );
177 return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT |
178 POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
179 }
180
181 if( ( ret = rsa_check_privkey( rsa ) ) != 0 )
182 {
183 rsa_free( rsa );
184 return( ret );
185 }
186
187 return( 0 );
188 }