This is a fork of the mbed port of axTLS

Dependents:   TLS_axTLS-Example HTTPSClientExample

Overview

This library is a fork from the mbed port of axTLS. It attempts to :

  • reduce the usage of dynamic memory
  • verify certificates with key size up to 2048 bits
  • provide a simple interface

Encryption

This library uses either RC4 or AES for encryption.

Memory usage

During the establishment of a connection, about 10KB of memory is allocated dynamically (it depends on certificates). Once the connection is established, the memory consumption is relatively low. This means that your program must not use too much static memory or allocate memory before you establish a TLS connection.

Certificates

Certificates are the major source of problem and will often be the reason why your program will crash. Due to memory constraint, there are some limitations on certificates :

  • Each certificate must not be bigger than 2KB
  • TLS client can only handle a chain of up to three certificates (excluding the root certificate). This means that the server must not send more than three certificates.

Also, this library can only load certificates following these specifications :

  • encoded in binary DER format (PKCS1)
  • The public key must use RSA only

Once the connection is established, you should free all loaded certificates by calling CertificateManager::clear(). This will free a few kilobytes (it depends on your certificates). In addition, to enable certificate verification during the connection, this library has a "precomputed mode". This mode uses much less memory than a normal certificate verification.

Normal mode

You need to copy the root certificate in binary-DER format on the mbed. Then in your code, let's say that your root certificate is saved on the mbed as "root.der", assuming that you include CertificateManager.h and that you created a LocalFileSystem, you can load this certificate as this ;

Load root certificate

CertificateManager::add("/local/root.der");
CertificateManager::load();

Do not forget that this mode takes quite a lot of memory ( the memory peak is high while verifying certificates) and will only work if the key size is not bigger than 1024 bits (otherwise it will crash while verifying certificates).

Precomputed mode

In this mode, you need to save the entire chain of certificates (in binary-DER format) including the root certificate on the mbed. In practice, this means that you must first retrieve all certificates that the server sends during a connection and then find the right root certificate. In your code, you must call CertificateManager::add for each certificate and in the right order : from the server certificate to the root certificate. Here is how you shoud load certificates in this mode :

Loadcertificates in precomputed mode

CertificateManager::add("/local/server1.der");
CertificateManager::add("/local/server2.der");
CertificateManager::add("/local/server3.der");
CertificateManager::add("/local/root.der");
CertificateManager::load(true);

Using this mode, you should be able to verify certificates with key size up to 2048 bits.

How do I find these certificates ?

I posted an entry in my notebook detailing how to get certificates from a server. You should be able to get all certificates you need except the root certificate. Here is a way how to get the root certificate on windows :

  1. Open (double-click) the last certificate sent by the server
  2. Go to details panel and click on the entry called Issuer. The first line gives you the name of this certificate and the second line indicates the company who created this certificate
  3. Open firefox
  4. Go to options, advanced panel and click on View Certificates
  5. Go to Authorities panel
  6. Choose the certificate whose name match the issuer of the last certificate sent by the server
  7. Export this certificate to binary-DER format.

Connect to mbed.org !

Import programTLS_axTLS-Example

Establishing a connection to mbed.org using TLS

Committer:
feb11
Date:
Thu Sep 12 15:18:04 2013 +0000
Revision:
0:85fceccc1a7c
intial import

Who changed what in which revision?

UserRevisionLine numberNew contents of line
feb11 0:85fceccc1a7c 1 /*
feb11 0:85fceccc1a7c 2 * Copyright (c) 2007, Cameron Rich
feb11 0:85fceccc1a7c 3 *
feb11 0:85fceccc1a7c 4 * All rights reserved.
feb11 0:85fceccc1a7c 5 *
feb11 0:85fceccc1a7c 6 * Redistribution and use in source and binary forms, with or without
feb11 0:85fceccc1a7c 7 * modification, are permitted provided that the following conditions are met:
feb11 0:85fceccc1a7c 8 *
feb11 0:85fceccc1a7c 9 * * Redistributions of source code must retain the above copyright notice,
feb11 0:85fceccc1a7c 10 * this list of conditions and the following disclaimer.
feb11 0:85fceccc1a7c 11 * * Redistributions in binary form must reproduce the above copyright notice,
feb11 0:85fceccc1a7c 12 * this list of conditions and the following disclaimer in the documentation
feb11 0:85fceccc1a7c 13 * and/or other materials provided with the distribution.
feb11 0:85fceccc1a7c 14 * * Neither the name of the axTLS project nor the names of its contributors
feb11 0:85fceccc1a7c 15 * may be used to endorse or promote products derived from this software
feb11 0:85fceccc1a7c 16 * without specific prior written permission.
feb11 0:85fceccc1a7c 17 *
feb11 0:85fceccc1a7c 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
feb11 0:85fceccc1a7c 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
feb11 0:85fceccc1a7c 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
feb11 0:85fceccc1a7c 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
feb11 0:85fceccc1a7c 22 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
feb11 0:85fceccc1a7c 23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
feb11 0:85fceccc1a7c 24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
feb11 0:85fceccc1a7c 25 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
feb11 0:85fceccc1a7c 26 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
feb11 0:85fceccc1a7c 27 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
feb11 0:85fceccc1a7c 28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
feb11 0:85fceccc1a7c 29 */
feb11 0:85fceccc1a7c 30
feb11 0:85fceccc1a7c 31 /**
feb11 0:85fceccc1a7c 32 * @file x509.c
feb11 0:85fceccc1a7c 33 *
feb11 0:85fceccc1a7c 34 * Certificate processing.
feb11 0:85fceccc1a7c 35 */
feb11 0:85fceccc1a7c 36
feb11 0:85fceccc1a7c 37 #include <time.h>
feb11 0:85fceccc1a7c 38 #include <stdio.h>
feb11 0:85fceccc1a7c 39 #include <stdlib.h>
feb11 0:85fceccc1a7c 40 #include <string.h>
feb11 0:85fceccc1a7c 41 #include "os_port.h"
feb11 0:85fceccc1a7c 42 #include "crypto_misc.h"
feb11 0:85fceccc1a7c 43 #include "sockets.h"
feb11 0:85fceccc1a7c 44 #include "config.h"
feb11 0:85fceccc1a7c 45 #ifdef CONFIG_SSL_CERT_VERIFICATION
feb11 0:85fceccc1a7c 46 #include "../../cert_manager.h"
feb11 0:85fceccc1a7c 47
feb11 0:85fceccc1a7c 48 /**
feb11 0:85fceccc1a7c 49 * Retrieve the signature from a certificate.
feb11 0:85fceccc1a7c 50 */
feb11 0:85fceccc1a7c 51 static const uint8_t *get_signature(const uint8_t *asn1_sig, int *len)
feb11 0:85fceccc1a7c 52 {
feb11 0:85fceccc1a7c 53 int offset = 0;
feb11 0:85fceccc1a7c 54 const uint8_t *ptr = NULL;
feb11 0:85fceccc1a7c 55
feb11 0:85fceccc1a7c 56 if (asn1_next_obj(asn1_sig, &offset, ASN1_SEQUENCE) < 0 ||
feb11 0:85fceccc1a7c 57 asn1_skip_obj(asn1_sig, &offset, ASN1_SEQUENCE))
feb11 0:85fceccc1a7c 58 goto end_get_sig;
feb11 0:85fceccc1a7c 59
feb11 0:85fceccc1a7c 60 if (asn1_sig[offset++] != ASN1_OCTET_STRING)
feb11 0:85fceccc1a7c 61 goto end_get_sig;
feb11 0:85fceccc1a7c 62 *len = get_asn1_length(asn1_sig, &offset);
feb11 0:85fceccc1a7c 63 ptr = &asn1_sig[offset]; /* all ok */
feb11 0:85fceccc1a7c 64
feb11 0:85fceccc1a7c 65 end_get_sig:
feb11 0:85fceccc1a7c 66 return ptr;
feb11 0:85fceccc1a7c 67 }
feb11 0:85fceccc1a7c 68
feb11 0:85fceccc1a7c 69 #endif
feb11 0:85fceccc1a7c 70
feb11 0:85fceccc1a7c 71 /**
feb11 0:85fceccc1a7c 72 * Construct a new x509 object.
feb11 0:85fceccc1a7c 73 * @return 0 if ok. < 0 if there was a problem.
feb11 0:85fceccc1a7c 74 */
feb11 0:85fceccc1a7c 75 int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx)
feb11 0:85fceccc1a7c 76 {
feb11 0:85fceccc1a7c 77
feb11 0:85fceccc1a7c 78 int begin_tbs, end_tbs;
feb11 0:85fceccc1a7c 79 int ret = X509_NOT_OK, offset = 0, cert_size = 0;
feb11 0:85fceccc1a7c 80 X509_CTX *x509_ctx;
feb11 0:85fceccc1a7c 81 BI_CTX *bi_ctx;
feb11 0:85fceccc1a7c 82 *ctx = (X509_CTX *)calloc(1, sizeof(X509_CTX));
feb11 0:85fceccc1a7c 83 x509_ctx = *ctx;
feb11 0:85fceccc1a7c 84 /* get the certificate size */
feb11 0:85fceccc1a7c 85 asn1_skip_obj(cert, &cert_size, ASN1_SEQUENCE);
feb11 0:85fceccc1a7c 86
feb11 0:85fceccc1a7c 87 if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0)
feb11 0:85fceccc1a7c 88 goto end_cert;
feb11 0:85fceccc1a7c 89
feb11 0:85fceccc1a7c 90 begin_tbs = offset; /* start of the tbs */
feb11 0:85fceccc1a7c 91 end_tbs = begin_tbs; /* work out the end of the tbs */
feb11 0:85fceccc1a7c 92 asn1_skip_obj(cert, &end_tbs, ASN1_SEQUENCE);
feb11 0:85fceccc1a7c 93 if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0)
feb11 0:85fceccc1a7c 94 goto end_cert;
feb11 0:85fceccc1a7c 95 if (cert[offset] == ASN1_EXPLICIT_TAG) /* optional version */
feb11 0:85fceccc1a7c 96 {
feb11 0:85fceccc1a7c 97 if (asn1_version(cert, &offset, x509_ctx))
feb11 0:85fceccc1a7c 98 goto end_cert;
feb11 0:85fceccc1a7c 99 }
feb11 0:85fceccc1a7c 100 if (asn1_skip_obj(cert, &offset, ASN1_INTEGER) || /* serial number */
feb11 0:85fceccc1a7c 101 asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0)
feb11 0:85fceccc1a7c 102 {
feb11 0:85fceccc1a7c 103 goto end_cert;
feb11 0:85fceccc1a7c 104 }
feb11 0:85fceccc1a7c 105
feb11 0:85fceccc1a7c 106 /* make sure the signature is ok */
feb11 0:85fceccc1a7c 107 if (asn1_signature_type(cert, &offset, x509_ctx))
feb11 0:85fceccc1a7c 108 {
feb11 0:85fceccc1a7c 109 ret = X509_VFY_ERROR_UNSUPPORTED_DIGEST;
feb11 0:85fceccc1a7c 110 goto end_cert;
feb11 0:85fceccc1a7c 111 }
feb11 0:85fceccc1a7c 112 if (asn1_name(cert, &offset, x509_ctx->ca_cert_dn) ||
feb11 0:85fceccc1a7c 113 asn1_validity(cert, &offset, x509_ctx) ||
feb11 0:85fceccc1a7c 114 asn1_name(cert, &offset, x509_ctx->cert_dn) ||
feb11 0:85fceccc1a7c 115 asn1_public_key(cert, &offset, x509_ctx))
feb11 0:85fceccc1a7c 116 {
feb11 0:85fceccc1a7c 117 goto end_cert;
feb11 0:85fceccc1a7c 118 }
feb11 0:85fceccc1a7c 119 bi_ctx = x509_ctx->rsa_ctx->bi_ctx;
feb11 0:85fceccc1a7c 120
feb11 0:85fceccc1a7c 121
feb11 0:85fceccc1a7c 122 #ifdef CONFIG_SSL_CERT_VERIFICATION /* only care if doing verification */
feb11 0:85fceccc1a7c 123
feb11 0:85fceccc1a7c 124 /* use the appropriate signature algorithm (SHA1/MD5/MD2) */
feb11 0:85fceccc1a7c 125
feb11 0:85fceccc1a7c 126 if (x509_ctx->sig_type == SIG_TYPE_MD5)
feb11 0:85fceccc1a7c 127 {
feb11 0:85fceccc1a7c 128 MD5_CTX md5_ctx;
feb11 0:85fceccc1a7c 129 uint8_t md5_dgst[MD5_SIZE];
feb11 0:85fceccc1a7c 130 MD5_Init(&md5_ctx);
feb11 0:85fceccc1a7c 131 MD5_Update(&md5_ctx, &cert[begin_tbs], end_tbs-begin_tbs);
feb11 0:85fceccc1a7c 132 MD5_Final(md5_dgst, &md5_ctx);
feb11 0:85fceccc1a7c 133 x509_ctx->digest = bi_import(bi_ctx, md5_dgst, MD5_SIZE);
feb11 0:85fceccc1a7c 134 }
feb11 0:85fceccc1a7c 135 else if (x509_ctx->sig_type == SIG_TYPE_SHA1)
feb11 0:85fceccc1a7c 136 {
feb11 0:85fceccc1a7c 137 SHA1_CTX sha_ctx;
feb11 0:85fceccc1a7c 138 uint8_t sha_dgst[SHA1_SIZE];
feb11 0:85fceccc1a7c 139 SHA1_Init(&sha_ctx);
feb11 0:85fceccc1a7c 140 SHA1_Update(&sha_ctx, &cert[begin_tbs], end_tbs-begin_tbs);
feb11 0:85fceccc1a7c 141 SHA1_Final(sha_dgst, &sha_ctx);
feb11 0:85fceccc1a7c 142 x509_ctx->digest = bi_import(bi_ctx, sha_dgst, SHA1_SIZE);
feb11 0:85fceccc1a7c 143 }
feb11 0:85fceccc1a7c 144 else if (x509_ctx->sig_type == SIG_TYPE_MD2)
feb11 0:85fceccc1a7c 145 {
feb11 0:85fceccc1a7c 146 MD2_CTX md2_ctx;
feb11 0:85fceccc1a7c 147 uint8_t md2_dgst[MD2_SIZE];
feb11 0:85fceccc1a7c 148 MD2_Init(&md2_ctx);
feb11 0:85fceccc1a7c 149 MD2_Update(&md2_ctx, &cert[begin_tbs], end_tbs-begin_tbs);
feb11 0:85fceccc1a7c 150 MD2_Final(md2_dgst, &md2_ctx);
feb11 0:85fceccc1a7c 151 x509_ctx->digest = bi_import(bi_ctx, md2_dgst, MD2_SIZE);
feb11 0:85fceccc1a7c 152 }
feb11 0:85fceccc1a7c 153
feb11 0:85fceccc1a7c 154 if (cert[offset] == ASN1_V3_DATA)
feb11 0:85fceccc1a7c 155 {
feb11 0:85fceccc1a7c 156 int suboffset;
feb11 0:85fceccc1a7c 157
feb11 0:85fceccc1a7c 158 ++offset;
feb11 0:85fceccc1a7c 159 get_asn1_length(cert, &offset);
feb11 0:85fceccc1a7c 160
feb11 0:85fceccc1a7c 161 if ((suboffset = asn1_find_subjectaltname(cert, offset)) > 0)
feb11 0:85fceccc1a7c 162 {
feb11 0:85fceccc1a7c 163 if (asn1_next_obj(cert, &suboffset, ASN1_OCTET_STRING) > 0)
feb11 0:85fceccc1a7c 164 {
feb11 0:85fceccc1a7c 165 int altlen;
feb11 0:85fceccc1a7c 166
feb11 0:85fceccc1a7c 167 if ((altlen = asn1_next_obj(cert,
feb11 0:85fceccc1a7c 168 &suboffset, ASN1_SEQUENCE)) > 0)
feb11 0:85fceccc1a7c 169 {
feb11 0:85fceccc1a7c 170 int endalt = suboffset + altlen;
feb11 0:85fceccc1a7c 171 int totalnames = 0;
feb11 0:85fceccc1a7c 172
feb11 0:85fceccc1a7c 173 while (suboffset < endalt)
feb11 0:85fceccc1a7c 174 {
feb11 0:85fceccc1a7c 175 int type = cert[suboffset++];
feb11 0:85fceccc1a7c 176 int dnslen = get_asn1_length(cert, &suboffset);
feb11 0:85fceccc1a7c 177
feb11 0:85fceccc1a7c 178 if (type == ASN1_CONTEXT_DNSNAME)
feb11 0:85fceccc1a7c 179 {
feb11 0:85fceccc1a7c 180 x509_ctx->subject_alt_dnsnames = (char**)
feb11 0:85fceccc1a7c 181 realloc(x509_ctx->subject_alt_dnsnames,
feb11 0:85fceccc1a7c 182 (totalnames + 2) * sizeof(char*));
feb11 0:85fceccc1a7c 183 x509_ctx->subject_alt_dnsnames[totalnames] =
feb11 0:85fceccc1a7c 184 (char*)malloc(dnslen + 1);
feb11 0:85fceccc1a7c 185 x509_ctx->subject_alt_dnsnames[totalnames+1] = NULL;
feb11 0:85fceccc1a7c 186 memcpy(x509_ctx->subject_alt_dnsnames[totalnames],
feb11 0:85fceccc1a7c 187 cert + suboffset, dnslen);
feb11 0:85fceccc1a7c 188 x509_ctx->subject_alt_dnsnames[
feb11 0:85fceccc1a7c 189 totalnames][dnslen] = 0;
feb11 0:85fceccc1a7c 190 ++totalnames;
feb11 0:85fceccc1a7c 191 }
feb11 0:85fceccc1a7c 192
feb11 0:85fceccc1a7c 193 suboffset += dnslen;
feb11 0:85fceccc1a7c 194 }
feb11 0:85fceccc1a7c 195 }
feb11 0:85fceccc1a7c 196 }
feb11 0:85fceccc1a7c 197 }
feb11 0:85fceccc1a7c 198 }
feb11 0:85fceccc1a7c 199
feb11 0:85fceccc1a7c 200 offset = end_tbs; /* skip the rest of v3 data */
feb11 0:85fceccc1a7c 201 if (asn1_skip_obj(cert, &offset, ASN1_SEQUENCE) ||
feb11 0:85fceccc1a7c 202 asn1_signature(cert, &offset, x509_ctx))
feb11 0:85fceccc1a7c 203 goto end_cert;
feb11 0:85fceccc1a7c 204
feb11 0:85fceccc1a7c 205 #endif
feb11 0:85fceccc1a7c 206 ret = X509_OK;
feb11 0:85fceccc1a7c 207 end_cert:
feb11 0:85fceccc1a7c 208 if (len)
feb11 0:85fceccc1a7c 209 {
feb11 0:85fceccc1a7c 210 *len = cert_size;
feb11 0:85fceccc1a7c 211 }
feb11 0:85fceccc1a7c 212
feb11 0:85fceccc1a7c 213 if (ret)
feb11 0:85fceccc1a7c 214 {
feb11 0:85fceccc1a7c 215 #ifdef CONFIG_SSL_FULL_MODE
feb11 0:85fceccc1a7c 216 printf("Error: Invalid X509 ASN.1 file (%s)\n",
feb11 0:85fceccc1a7c 217 x509_display_error(ret));
feb11 0:85fceccc1a7c 218 #endif
feb11 0:85fceccc1a7c 219 x509_free(x509_ctx);
feb11 0:85fceccc1a7c 220 *ctx = NULL;
feb11 0:85fceccc1a7c 221 }
feb11 0:85fceccc1a7c 222 return ret;
feb11 0:85fceccc1a7c 223 }
feb11 0:85fceccc1a7c 224
feb11 0:85fceccc1a7c 225 /**
feb11 0:85fceccc1a7c 226 * Free an X.509 object's resources.
feb11 0:85fceccc1a7c 227 */
feb11 0:85fceccc1a7c 228 void x509_free(X509_CTX *x509_ctx)
feb11 0:85fceccc1a7c 229 {
feb11 0:85fceccc1a7c 230 X509_CTX *next;
feb11 0:85fceccc1a7c 231 int i;
feb11 0:85fceccc1a7c 232
feb11 0:85fceccc1a7c 233 if (x509_ctx == NULL) /* if already null, then don't bother */
feb11 0:85fceccc1a7c 234 return;
feb11 0:85fceccc1a7c 235
feb11 0:85fceccc1a7c 236 for (i = 0; i < X509_NUM_DN_TYPES; i++)
feb11 0:85fceccc1a7c 237 {
feb11 0:85fceccc1a7c 238 free(x509_ctx->ca_cert_dn[i]);
feb11 0:85fceccc1a7c 239 free(x509_ctx->cert_dn[i]);
feb11 0:85fceccc1a7c 240 }
feb11 0:85fceccc1a7c 241
feb11 0:85fceccc1a7c 242 free(x509_ctx->signature);
feb11 0:85fceccc1a7c 243
feb11 0:85fceccc1a7c 244 #ifdef CONFIG_SSL_CERT_VERIFICATION
feb11 0:85fceccc1a7c 245 if (x509_ctx->digest)
feb11 0:85fceccc1a7c 246 {
feb11 0:85fceccc1a7c 247 bi_free(x509_ctx->rsa_ctx->bi_ctx, x509_ctx->digest);
feb11 0:85fceccc1a7c 248 }
feb11 0:85fceccc1a7c 249
feb11 0:85fceccc1a7c 250 if (x509_ctx->subject_alt_dnsnames)
feb11 0:85fceccc1a7c 251 {
feb11 0:85fceccc1a7c 252 for (i = 0; x509_ctx->subject_alt_dnsnames[i]; ++i)
feb11 0:85fceccc1a7c 253 free(x509_ctx->subject_alt_dnsnames[i]);
feb11 0:85fceccc1a7c 254
feb11 0:85fceccc1a7c 255 free(x509_ctx->subject_alt_dnsnames);
feb11 0:85fceccc1a7c 256 }
feb11 0:85fceccc1a7c 257 #endif
feb11 0:85fceccc1a7c 258
feb11 0:85fceccc1a7c 259 RSA_free(x509_ctx->rsa_ctx);
feb11 0:85fceccc1a7c 260 next = x509_ctx->next;
feb11 0:85fceccc1a7c 261 free(x509_ctx);
feb11 0:85fceccc1a7c 262 x509_free(next); /* clear the chain */
feb11 0:85fceccc1a7c 263 }
feb11 0:85fceccc1a7c 264
feb11 0:85fceccc1a7c 265 #ifdef CONFIG_SSL_CERT_VERIFICATION
feb11 0:85fceccc1a7c 266 /**
feb11 0:85fceccc1a7c 267 * Take a signature and decrypt it.
feb11 0:85fceccc1a7c 268 */
feb11 0:85fceccc1a7c 269 bigint *sig_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len,
feb11 0:85fceccc1a7c 270 bigint *modulus, bigint *pub_exp)
feb11 0:85fceccc1a7c 271 {
feb11 0:85fceccc1a7c 272 int i, size;
feb11 0:85fceccc1a7c 273 bigint *decrypted_bi, *dat_bi;
feb11 0:85fceccc1a7c 274 bigint *bir = NULL;
feb11 0:85fceccc1a7c 275 uint8_t *block = (uint8_t *)alloca(sig_len);
feb11 0:85fceccc1a7c 276
feb11 0:85fceccc1a7c 277 /* decrypt */
feb11 0:85fceccc1a7c 278 dat_bi = bi_import(ctx, sig, sig_len);
feb11 0:85fceccc1a7c 279 ctx->mod_offset = BIGINT_M_OFFSET;
feb11 0:85fceccc1a7c 280
feb11 0:85fceccc1a7c 281 /* convert to a normal block */
feb11 0:85fceccc1a7c 282 decrypted_bi = bi_mod_power2(ctx, dat_bi, modulus, pub_exp);
feb11 0:85fceccc1a7c 283
feb11 0:85fceccc1a7c 284 bi_export(ctx, decrypted_bi, block, sig_len);
feb11 0:85fceccc1a7c 285 ctx->mod_offset = BIGINT_M_OFFSET;
feb11 0:85fceccc1a7c 286
feb11 0:85fceccc1a7c 287 i = 10; /* start at the first possible non-padded byte */
feb11 0:85fceccc1a7c 288 while (block[i++] && i < sig_len);
feb11 0:85fceccc1a7c 289 size = sig_len - i;
feb11 0:85fceccc1a7c 290
feb11 0:85fceccc1a7c 291 /* get only the bit we want */
feb11 0:85fceccc1a7c 292 if (size > 0)
feb11 0:85fceccc1a7c 293 {
feb11 0:85fceccc1a7c 294 int len = 0;
feb11 0:85fceccc1a7c 295 const uint8_t *sig_ptr = get_signature(&block[i], &len);
feb11 0:85fceccc1a7c 296
feb11 0:85fceccc1a7c 297 if (sig_ptr)
feb11 0:85fceccc1a7c 298 {
feb11 0:85fceccc1a7c 299 bir = bi_import(ctx, sig_ptr, len);
feb11 0:85fceccc1a7c 300 }
feb11 0:85fceccc1a7c 301 }
feb11 0:85fceccc1a7c 302
feb11 0:85fceccc1a7c 303 /* save a few bytes of memory */
feb11 0:85fceccc1a7c 304 bi_clear_cache(ctx);
feb11 0:85fceccc1a7c 305 return bir;
feb11 0:85fceccc1a7c 306 }
feb11 0:85fceccc1a7c 307
feb11 0:85fceccc1a7c 308
feb11 0:85fceccc1a7c 309 /**
feb11 0:85fceccc1a7c 310 * Do some basic checks on the certificate chain.
feb11 0:85fceccc1a7c 311 *
feb11 0:85fceccc1a7c 312 * Certificate verification consists of a number of checks:
feb11 0:85fceccc1a7c 313 * - The date of the certificate is after the start date.
feb11 0:85fceccc1a7c 314 * - The date of the certificate is before the finish date.
feb11 0:85fceccc1a7c 315 * - A root certificate exists in the certificate store.
feb11 0:85fceccc1a7c 316 * - That the certificate(s) are not self-signed.
feb11 0:85fceccc1a7c 317 * - The certificate chain is valid.
feb11 0:85fceccc1a7c 318 * - The signature of the certificate is valid.
feb11 0:85fceccc1a7c 319 */
feb11 0:85fceccc1a7c 320 int x509_verify(PrecomputedCertificate *cert)
feb11 0:85fceccc1a7c 321 {
feb11 0:85fceccc1a7c 322
feb11 0:85fceccc1a7c 323 int ret = X509_OK;
feb11 0:85fceccc1a7c 324 PrecomputedCertificate *next_cert = NULL;
feb11 0:85fceccc1a7c 325 int match_ca_cert = 0;
feb11 0:85fceccc1a7c 326 uint8_t is_self_signed = 0;
feb11 0:85fceccc1a7c 327 uint8_t *mod = NULL, *expn = NULL;
feb11 0:85fceccc1a7c 328 bigint *bi_mod = NULL, *bi_expn = NULL;
feb11 0:85fceccc1a7c 329 BI_CTX *bi_ctx = NULL;
feb11 0:85fceccc1a7c 330 char precomputed = is_precomputed();
feb11 0:85fceccc1a7c 331
feb11 0:85fceccc1a7c 332 if (cert == NULL)
feb11 0:85fceccc1a7c 333 {
feb11 0:85fceccc1a7c 334 ret = X509_VFY_ERROR_NO_TRUSTED_CERT;
feb11 0:85fceccc1a7c 335 goto end_verify;
feb11 0:85fceccc1a7c 336 }
feb11 0:85fceccc1a7c 337 /* a self-signed certificate that is not in the CA store - use this
feb11 0:85fceccc1a7c 338 to check the signature */
feb11 0:85fceccc1a7c 339 if (asn1_compare_dn(cert->ca_cert_dn, cert->cert_dn) == 0)
feb11 0:85fceccc1a7c 340 {
feb11 0:85fceccc1a7c 341 is_self_signed = 1;
feb11 0:85fceccc1a7c 342 if(precomputed)
feb11 0:85fceccc1a7c 343 {
feb11 0:85fceccc1a7c 344 mod = cert->mod;
feb11 0:85fceccc1a7c 345 expn = cert->expn;
feb11 0:85fceccc1a7c 346 }
feb11 0:85fceccc1a7c 347 else
feb11 0:85fceccc1a7c 348 {
feb11 0:85fceccc1a7c 349 bi_ctx = bi_initialize();
feb11 0:85fceccc1a7c 350 bi_mod = bi_import(bi_ctx, cert->mod, cert->mod_len);
feb11 0:85fceccc1a7c 351 bi_expn = bi_import(bi_ctx, cert->expn, cert->expn_len);
feb11 0:85fceccc1a7c 352 }
feb11 0:85fceccc1a7c 353 }
feb11 0:85fceccc1a7c 354
feb11 0:85fceccc1a7c 355 next_cert = cert->next;
feb11 0:85fceccc1a7c 356
feb11 0:85fceccc1a7c 357 /* last cert in the chain - look for a trusted cert */
feb11 0:85fceccc1a7c 358 if (next_cert == NULL)
feb11 0:85fceccc1a7c 359 {
feb11 0:85fceccc1a7c 360 if(precomputed)
feb11 0:85fceccc1a7c 361 {
feb11 0:85fceccc1a7c 362 PrecomputedCertificate tmp = get_precomputed_cert(cert->cert_dn, cert->ca_cert_dn);
feb11 0:85fceccc1a7c 363 mod = tmp.mod;
feb11 0:85fceccc1a7c 364 expn = tmp.expn;
feb11 0:85fceccc1a7c 365 }
feb11 0:85fceccc1a7c 366 else
feb11 0:85fceccc1a7c 367 {
feb11 0:85fceccc1a7c 368 X509_CTX *root = get_cert(cert->ca_cert_dn);
feb11 0:85fceccc1a7c 369 bi_ctx = root->rsa_ctx->bi_ctx;
feb11 0:85fceccc1a7c 370 bi_mod = bi_clone(bi_ctx,root->rsa_ctx->m);
feb11 0:85fceccc1a7c 371 bi_expn = bi_clone(bi_ctx, root->rsa_ctx->e);
feb11 0:85fceccc1a7c 372 }
feb11 0:85fceccc1a7c 373 }
feb11 0:85fceccc1a7c 374 else if (asn1_compare_dn(cert->ca_cert_dn, next_cert->cert_dn) != 0)
feb11 0:85fceccc1a7c 375 {
feb11 0:85fceccc1a7c 376 /* check the chain */
feb11 0:85fceccc1a7c 377 ret = X509_VFY_ERROR_INVALID_CHAIN;
feb11 0:85fceccc1a7c 378 goto end_verify;
feb11 0:85fceccc1a7c 379 }
feb11 0:85fceccc1a7c 380 else /* use the next certificate in the chain for signature verify */
feb11 0:85fceccc1a7c 381 {
feb11 0:85fceccc1a7c 382 if(precomputed)
feb11 0:85fceccc1a7c 383 {
feb11 0:85fceccc1a7c 384 mod = next_cert->mod;
feb11 0:85fceccc1a7c 385 expn = next_cert->expn;
feb11 0:85fceccc1a7c 386 }
feb11 0:85fceccc1a7c 387 else
feb11 0:85fceccc1a7c 388 {
feb11 0:85fceccc1a7c 389 bi_ctx = bi_initialize();
feb11 0:85fceccc1a7c 390 bi_mod = bi_import(bi_ctx, next_cert->mod, next_cert->mod_len);
feb11 0:85fceccc1a7c 391 bi_expn = bi_import(bi_ctx, next_cert->expn, next_cert->expn_len);
feb11 0:85fceccc1a7c 392 }
feb11 0:85fceccc1a7c 393 }
feb11 0:85fceccc1a7c 394
feb11 0:85fceccc1a7c 395 /* cert is self signed */
feb11 0:85fceccc1a7c 396 if (!match_ca_cert && is_self_signed)
feb11 0:85fceccc1a7c 397 {
feb11 0:85fceccc1a7c 398 ret = X509_VFY_ERROR_SELF_SIGNED;
feb11 0:85fceccc1a7c 399 goto end_verify;
feb11 0:85fceccc1a7c 400 }
feb11 0:85fceccc1a7c 401
feb11 0:85fceccc1a7c 402 /* check the signature */
feb11 0:85fceccc1a7c 403 if(precomputed)
feb11 0:85fceccc1a7c 404 {
feb11 0:85fceccc1a7c 405 PrecomputedCertificate pc = get_precomputed_cert(cert->cert_dn, cert->ca_cert_dn);
feb11 0:85fceccc1a7c 406
feb11 0:85fceccc1a7c 407 if(memcmp(cert->sig, pc.sig, pc.sig_len)
feb11 0:85fceccc1a7c 408 || memcmp(cert->digest, pc.digest, pc.digest_len)
feb11 0:85fceccc1a7c 409 || memcmp(mod, pc.mod, pc.mod_len)
feb11 0:85fceccc1a7c 410 || memcmp(expn, pc.expn, pc.expn_len))
feb11 0:85fceccc1a7c 411 ret = X509_VFY_ERROR_BAD_SIGNATURE;
feb11 0:85fceccc1a7c 412 }
feb11 0:85fceccc1a7c 413 else
feb11 0:85fceccc1a7c 414 {
feb11 0:85fceccc1a7c 415 bigint* cert_sig = sig_verify(bi_ctx, cert->sig, cert->sig_len,
feb11 0:85fceccc1a7c 416 bi_mod, bi_expn);
feb11 0:85fceccc1a7c 417
feb11 0:85fceccc1a7c 418 if (cert_sig && cert->digest)
feb11 0:85fceccc1a7c 419 {
feb11 0:85fceccc1a7c 420 uint8_t paddingLength = 0;
feb11 0:85fceccc1a7c 421 uint8_t digest[64];
feb11 0:85fceccc1a7c 422 bi_export(bi_ctx, cert_sig, digest, sizeof(digest));
feb11 0:85fceccc1a7c 423 while(digest[paddingLength] == 0) paddingLength++;
feb11 0:85fceccc1a7c 424 uint8_t digest_len = 64 - paddingLength;
feb11 0:85fceccc1a7c 425 if (memcmp(digest, cert->digest, digest_len) != 0)
feb11 0:85fceccc1a7c 426 ret = X509_VFY_ERROR_BAD_SIGNATURE;
feb11 0:85fceccc1a7c 427 }
feb11 0:85fceccc1a7c 428 else
feb11 0:85fceccc1a7c 429 {
feb11 0:85fceccc1a7c 430 ret = X509_VFY_ERROR_BAD_SIGNATURE;
feb11 0:85fceccc1a7c 431 }
feb11 0:85fceccc1a7c 432 if(is_self_signed || next_cert != NULL)
feb11 0:85fceccc1a7c 433 bi_terminate(bi_ctx);
feb11 0:85fceccc1a7c 434 }
feb11 0:85fceccc1a7c 435
feb11 0:85fceccc1a7c 436
feb11 0:85fceccc1a7c 437 if (ret)
feb11 0:85fceccc1a7c 438 goto end_verify;
feb11 0:85fceccc1a7c 439
feb11 0:85fceccc1a7c 440 /* go down the certificate chain using recursion. */
feb11 0:85fceccc1a7c 441 if (next_cert != NULL)
feb11 0:85fceccc1a7c 442 {
feb11 0:85fceccc1a7c 443 ret = x509_verify(next_cert);
feb11 0:85fceccc1a7c 444 }
feb11 0:85fceccc1a7c 445
feb11 0:85fceccc1a7c 446 end_verify:
feb11 0:85fceccc1a7c 447 return ret;
feb11 0:85fceccc1a7c 448 }
feb11 0:85fceccc1a7c 449 #endif
feb11 0:85fceccc1a7c 450
feb11 0:85fceccc1a7c 451 #if defined (CONFIG_SSL_FULL_MODE)
feb11 0:85fceccc1a7c 452 /**
feb11 0:85fceccc1a7c 453 * Used for diagnostics.
feb11 0:85fceccc1a7c 454 */
feb11 0:85fceccc1a7c 455 static const char *not_part_of_cert = "<Not Part Of Certificate>";
feb11 0:85fceccc1a7c 456 void x509_print(const X509_CTX *cert, CA_CERT_CTX *ca_cert_ctx)
feb11 0:85fceccc1a7c 457 {
feb11 0:85fceccc1a7c 458 if (cert == NULL)
feb11 0:85fceccc1a7c 459 return;
feb11 0:85fceccc1a7c 460
feb11 0:85fceccc1a7c 461 printf("=== CERTIFICATE ISSUED TO ===\n");
feb11 0:85fceccc1a7c 462 printf("Common Name (CN):\t\t");
feb11 0:85fceccc1a7c 463 printf("%s\r\n", cert->cert_dn[X509_COMMON_NAME] ?
feb11 0:85fceccc1a7c 464 cert->cert_dn[X509_COMMON_NAME] : not_part_of_cert);
feb11 0:85fceccc1a7c 465
feb11 0:85fceccc1a7c 466 printf("Organization (O):\t\t");
feb11 0:85fceccc1a7c 467 printf("%s\r\n", cert->cert_dn[X509_ORGANIZATION] ?
feb11 0:85fceccc1a7c 468 cert->cert_dn[X509_ORGANIZATION] : not_part_of_cert);
feb11 0:85fceccc1a7c 469
feb11 0:85fceccc1a7c 470 printf("Organizational Unit (OU):\t");
feb11 0:85fceccc1a7c 471 printf("%s\r\n", cert->cert_dn[X509_ORGANIZATIONAL_UNIT] ?
feb11 0:85fceccc1a7c 472 cert->cert_dn[X509_ORGANIZATIONAL_UNIT] : not_part_of_cert);
feb11 0:85fceccc1a7c 473
feb11 0:85fceccc1a7c 474 printf("=== CERTIFICATE ISSUED BY ===\r\n");
feb11 0:85fceccc1a7c 475 printf("Common Name (CN):\t\t");
feb11 0:85fceccc1a7c 476 printf("%s\r\n", cert->ca_cert_dn[X509_COMMON_NAME] ?
feb11 0:85fceccc1a7c 477 cert->ca_cert_dn[X509_COMMON_NAME] : not_part_of_cert);
feb11 0:85fceccc1a7c 478
feb11 0:85fceccc1a7c 479 printf("Organization (O):\t\t");
feb11 0:85fceccc1a7c 480 printf("%s\r\n", cert->ca_cert_dn[X509_ORGANIZATION] ?
feb11 0:85fceccc1a7c 481 cert->ca_cert_dn[X509_ORGANIZATION] : not_part_of_cert);
feb11 0:85fceccc1a7c 482
feb11 0:85fceccc1a7c 483 printf("Organizational Unit (OU):\t");
feb11 0:85fceccc1a7c 484 printf("%s\r\n", cert->ca_cert_dn[X509_ORGANIZATIONAL_UNIT] ?
feb11 0:85fceccc1a7c 485 cert->ca_cert_dn[X509_ORGANIZATIONAL_UNIT] : not_part_of_cert);
feb11 0:85fceccc1a7c 486
feb11 0:85fceccc1a7c 487 printf("Not Before:\t\t\t%s\r\n", ctime(&cert->not_before));
feb11 0:85fceccc1a7c 488 printf("Not After:\t\t\t%s\r\n", ctime(&cert->not_after));
feb11 0:85fceccc1a7c 489 printf("RSA bitsize:\t\t\t%d\r\n", cert->rsa_ctx->num_octets*8);
feb11 0:85fceccc1a7c 490 printf("Sig Type:\t\t\t");
feb11 0:85fceccc1a7c 491 switch (cert->sig_type)
feb11 0:85fceccc1a7c 492 {
feb11 0:85fceccc1a7c 493 case SIG_TYPE_MD5:
feb11 0:85fceccc1a7c 494 printf("MD5\r\n");
feb11 0:85fceccc1a7c 495 break;
feb11 0:85fceccc1a7c 496 case SIG_TYPE_SHA1:
feb11 0:85fceccc1a7c 497 printf("SHA1\r\n");
feb11 0:85fceccc1a7c 498 break;
feb11 0:85fceccc1a7c 499 case SIG_TYPE_MD2:
feb11 0:85fceccc1a7c 500 printf("MD2\r\n");
feb11 0:85fceccc1a7c 501 break;
feb11 0:85fceccc1a7c 502 default:
feb11 0:85fceccc1a7c 503 printf("Unrecognized: %d\r\n", cert->sig_type);
feb11 0:85fceccc1a7c 504 break;
feb11 0:85fceccc1a7c 505 }
feb11 0:85fceccc1a7c 506
feb11 0:85fceccc1a7c 507 if (ca_cert_ctx)
feb11 0:85fceccc1a7c 508 {
feb11 0:85fceccc1a7c 509 // printf("Verify:\t\t\t\t%s\r\n",
feb11 0:85fceccc1a7c 510 // x509_display_error(x509_verify(cert)));
feb11 0:85fceccc1a7c 511 }
feb11 0:85fceccc1a7c 512
feb11 0:85fceccc1a7c 513 #if 0
feb11 0:85fceccc1a7c 514 print_blob("Signature", cert->signature, cert->sig_len);
feb11 0:85fceccc1a7c 515 bi_print("Modulus", cert->rsa_ctx->m);
feb11 0:85fceccc1a7c 516 bi_print("Pub Exp", cert->rsa_ctx->e);
feb11 0:85fceccc1a7c 517 #endif
feb11 0:85fceccc1a7c 518
feb11 0:85fceccc1a7c 519 if (ca_cert_ctx)
feb11 0:85fceccc1a7c 520 {
feb11 0:85fceccc1a7c 521 x509_print(cert->next, ca_cert_ctx);
feb11 0:85fceccc1a7c 522 }
feb11 0:85fceccc1a7c 523
feb11 0:85fceccc1a7c 524 TTY_FLUSH();
feb11 0:85fceccc1a7c 525 }
feb11 0:85fceccc1a7c 526
feb11 0:85fceccc1a7c 527 const char * x509_display_error(int error)
feb11 0:85fceccc1a7c 528 {
feb11 0:85fceccc1a7c 529 switch (error)
feb11 0:85fceccc1a7c 530 {
feb11 0:85fceccc1a7c 531 case X509_OK:
feb11 0:85fceccc1a7c 532 return "Certificate verify successful";
feb11 0:85fceccc1a7c 533
feb11 0:85fceccc1a7c 534 case X509_NOT_OK:
feb11 0:85fceccc1a7c 535 return "X509 not ok";
feb11 0:85fceccc1a7c 536
feb11 0:85fceccc1a7c 537 case X509_VFY_ERROR_NO_TRUSTED_CERT:
feb11 0:85fceccc1a7c 538 return "No trusted cert is available";
feb11 0:85fceccc1a7c 539
feb11 0:85fceccc1a7c 540 case X509_VFY_ERROR_BAD_SIGNATURE:
feb11 0:85fceccc1a7c 541 return "Bad signature";
feb11 0:85fceccc1a7c 542
feb11 0:85fceccc1a7c 543 case X509_VFY_ERROR_NOT_YET_VALID:
feb11 0:85fceccc1a7c 544 return "Cert is not yet valid";
feb11 0:85fceccc1a7c 545
feb11 0:85fceccc1a7c 546 case X509_VFY_ERROR_EXPIRED:
feb11 0:85fceccc1a7c 547 return "Cert has expired";
feb11 0:85fceccc1a7c 548
feb11 0:85fceccc1a7c 549 case X509_VFY_ERROR_SELF_SIGNED:
feb11 0:85fceccc1a7c 550 return "Cert is self-signed";
feb11 0:85fceccc1a7c 551
feb11 0:85fceccc1a7c 552 case X509_VFY_ERROR_INVALID_CHAIN:
feb11 0:85fceccc1a7c 553 return "Chain is invalid (check order of certs)";
feb11 0:85fceccc1a7c 554
feb11 0:85fceccc1a7c 555 case X509_VFY_ERROR_UNSUPPORTED_DIGEST:
feb11 0:85fceccc1a7c 556 return "Unsupported digest";
feb11 0:85fceccc1a7c 557
feb11 0:85fceccc1a7c 558 case X509_INVALID_PRIV_KEY:
feb11 0:85fceccc1a7c 559 return "Invalid private key";
feb11 0:85fceccc1a7c 560
feb11 0:85fceccc1a7c 561 case X509_KEY_SIZE_TOO_BIG:
feb11 0:85fceccc1a7c 562 return "Only keys less or equal to 1024 bits are supported";
feb11 0:85fceccc1a7c 563
feb11 0:85fceccc1a7c 564 default:
feb11 0:85fceccc1a7c 565 return "Unknown";
feb11 0:85fceccc1a7c 566 }
feb11 0:85fceccc1a7c 567 }
feb11 0:85fceccc1a7c 568 #endif /* CONFIG_SSL_FULL_MODE */
feb11 0:85fceccc1a7c 569
feb11 0:85fceccc1a7c 570
feb11 0:85fceccc1a7c 571