pkcs5.c

Go to the documentation of this file.
00001 
00016 #include "includes.h"
00017 
00018 #include "common.h"
00019 #include "crypto.h"
00020 #include "md5.h"
00021 #include "asn1.h"
00022 #include "pkcs5.h"
00023 
00024 
00025 struct pkcs5_params {
00026         enum pkcs5_alg {
00027                 PKCS5_ALG_UNKNOWN,
00028                 PKCS5_ALG_MD5_DES_CBC
00029         } alg;
00030         u8 salt[8];
00031         size_t salt_len;
00032         unsigned int iter_count;
00033 };
00034 
00035 
00036 enum pkcs5_alg pkcs5_get_alg(struct asn1_oid *oid)
00037 {
00038         if (oid->len == 7 &&
00039             oid->oid[0] == 1 /* iso */ &&
00040             oid->oid[1] == 2 /* member-body */ &&
00041             oid->oid[2] == 840 /* us */ &&
00042             oid->oid[3] == 113549 /* rsadsi */ &&
00043             oid->oid[4] == 1 /* pkcs */ &&
00044             oid->oid[5] == 5 /* pkcs-5 */ &&
00045             oid->oid[6] == 3 /* pbeWithMD5AndDES-CBC */)
00046                 return PKCS5_ALG_MD5_DES_CBC;
00047 
00048         return PKCS5_ALG_UNKNOWN;
00049 }
00050 
00051 
00052 static int pkcs5_get_params(const u8 *enc_alg, size_t enc_alg_len,
00053                             struct pkcs5_params *params)
00054 {
00055         struct asn1_hdr hdr;
00056         const u8 *enc_alg_end, *pos, *end;
00057         struct asn1_oid oid;
00058         char obuf[80];
00059 
00060         /* AlgorithmIdentifier */
00061 
00062         enc_alg_end = enc_alg + enc_alg_len;
00063 
00064         os_memset(params, 0, sizeof(*params));
00065 
00066         if (asn1_get_oid(enc_alg, enc_alg_end - enc_alg, &oid, &pos)) {
00067                 wpa_printf(MSG_DEBUG, "PKCS #5: Failed to parse OID "
00068                            "(algorithm)");
00069                 return -1;
00070         }
00071 
00072         asn1_oid_to_str(&oid, obuf, sizeof(obuf));
00073         wpa_printf(MSG_DEBUG, "PKCS #5: encryption algorithm %s", obuf);
00074         params->alg = pkcs5_get_alg(&oid);
00075         if (params->alg == PKCS5_ALG_UNKNOWN) {
00076                 wpa_printf(MSG_INFO, "PKCS #5: unsupported encryption "
00077                            "algorithm %s", obuf);
00078                 return -1;
00079         }
00080 
00081         /*
00082          * PKCS#5, Section 8
00083          * PBEParameter ::= SEQUENCE {
00084          *   salt OCTET STRING SIZE(8),
00085          *   iterationCount INTEGER }
00086          */
00087 
00088         if (asn1_get_next(pos, enc_alg_end - pos, &hdr) < 0 ||
00089             hdr.class != ASN1_CLASS_UNIVERSAL ||
00090             hdr.tag != ASN1_TAG_SEQUENCE) {
00091                 wpa_printf(MSG_DEBUG, "PKCS #5: Expected SEQUENCE "
00092                            "(PBEParameter) - found class %d tag 0x%x",
00093                            hdr.class, hdr.tag);
00094                 return -1;
00095         }
00096         pos = hdr.payload;
00097         end = hdr.payload + hdr.length;
00098 
00099         /* salt OCTET STRING SIZE(8) */
00100         if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
00101             hdr.class != ASN1_CLASS_UNIVERSAL ||
00102             hdr.tag != ASN1_TAG_OCTETSTRING ||
00103             hdr.length != 8) {
00104                 wpa_printf(MSG_DEBUG, "PKCS #5: Expected OCTETSTRING SIZE(8) "
00105                            "(salt) - found class %d tag 0x%x size %d",
00106                            hdr.class, hdr.tag, hdr.length);
00107                 return -1;
00108         }
00109         pos = hdr.payload + hdr.length;
00110         os_memcpy(params->salt, hdr.payload, hdr.length);
00111         params->salt_len = hdr.length;
00112         wpa_hexdump(MSG_DEBUG, "PKCS #5: salt",
00113                     params->salt, params->salt_len);
00114 
00115         /* iterationCount INTEGER */
00116         if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
00117             hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) {
00118                 wpa_printf(MSG_DEBUG, "PKCS #5: Expected INTEGER - found "
00119                            "class %d tag 0x%x", hdr.class, hdr.tag);
00120                 return -1;
00121         }
00122         if (hdr.length == 1)
00123                 params->iter_count = *hdr.payload;
00124         else if (hdr.length == 2)
00125                 params->iter_count = WPA_GET_BE16(hdr.payload);
00126         else if (hdr.length == 4)
00127                 params->iter_count = WPA_GET_BE32(hdr.payload);
00128         else {
00129                 wpa_hexdump(MSG_DEBUG, "PKCS #5: Unsupported INTEGER value "
00130                             " (iterationCount)",
00131                             hdr.payload, hdr.length);
00132                 return -1;
00133         }
00134         wpa_printf(MSG_DEBUG, "PKCS #5: iterationCount=0x%x",
00135                    params->iter_count);
00136         if (params->iter_count == 0 || params->iter_count > 0xffff) {
00137                 wpa_printf(MSG_INFO, "PKCS #5: Unsupported "
00138                            "iterationCount=0x%x", params->iter_count);
00139                 return -1;
00140         }
00141 
00142         return 0;
00143 }
00144 
00145 
00146 static struct crypto_cipher * pkcs5_crypto_init(struct pkcs5_params *params,
00147                                                 const char *passwd)
00148 {
00149         unsigned int i;
00150         u8 hash[MD5_MAC_LEN];
00151         const u8 *addr[2];
00152         size_t len[2];
00153 
00154         if (params->alg != PKCS5_ALG_MD5_DES_CBC)
00155                 return NULL;
00156 
00157         addr[0] = (const u8 *) passwd;
00158         len[0] = os_strlen(passwd);
00159         addr[1] = params->salt;
00160         len[1] = params->salt_len;
00161         if (md5_vector(2, addr, len, hash) < 0)
00162                 return NULL;
00163         addr[0] = hash;
00164         len[0] = MD5_MAC_LEN;
00165         for (i = 1; i < params->iter_count; i++) {
00166                 if (md5_vector(1, addr, len, hash) < 0)
00167                         return NULL;
00168         }
00169         /* TODO: DES key parity bits(?) */
00170         wpa_hexdump_key(MSG_DEBUG, "PKCS #5: DES key", hash, 8);
00171         wpa_hexdump_key(MSG_DEBUG, "PKCS #5: DES IV", hash + 8, 8);
00172 
00173         return crypto_cipher_init(CRYPTO_CIPHER_ALG_DES, hash + 8, hash, 8);
00174 }
00175 
00176 
00177 u8 * pkcs5_decrypt(const u8 *enc_alg, size_t enc_alg_len,
00178                    const u8 *enc_data, size_t enc_data_len,
00179                    const char *passwd, size_t *data_len)
00180 {
00181         struct crypto_cipher *ctx;
00182         u8 *eb, pad;
00183         struct pkcs5_params params;
00184         unsigned int i;
00185 
00186         if (pkcs5_get_params(enc_alg, enc_alg_len, &params) < 0) {
00187                 wpa_printf(MSG_DEBUG, "PKCS #5: Unsupported parameters");
00188                 return NULL;
00189         }
00190 
00191         ctx = pkcs5_crypto_init(&params, passwd);
00192         if (ctx == NULL) {
00193                 wpa_printf(MSG_DEBUG, "PKCS #5: Failed to initialize crypto");
00194                 return NULL;
00195         }
00196 
00197         /* PKCS #5, Section 7 - Decryption process */
00198         if (enc_data_len < 16 || enc_data_len % 8) {
00199                 wpa_printf(MSG_INFO, "PKCS #5: invalid length of ciphertext "
00200                            "%d", (int) enc_data_len);
00201                 crypto_cipher_deinit(ctx);
00202                 return NULL;
00203         }
00204 
00205         eb = os_malloc(enc_data_len);
00206         if (eb == NULL) {
00207                 crypto_cipher_deinit(ctx);
00208                 return NULL;
00209         }
00210 
00211         if (crypto_cipher_decrypt(ctx, enc_data, eb, enc_data_len) < 0) {
00212                 wpa_printf(MSG_DEBUG, "PKCS #5: Failed to decrypt EB");
00213                 crypto_cipher_deinit(ctx);
00214                 os_free(eb);
00215                 return NULL;
00216         }
00217         crypto_cipher_deinit(ctx);
00218 
00219         pad = eb[enc_data_len - 1];
00220         if (pad > 8) {
00221                 wpa_printf(MSG_INFO, "PKCS #5: Invalid PS octet 0x%x", pad);
00222                 os_free(eb);
00223                 return NULL;
00224         }
00225         for (i = enc_data_len - pad; i < enc_data_len; i++) {
00226                 if (eb[i] != pad) {
00227                         wpa_hexdump(MSG_INFO, "PKCS #5: Invalid PS",
00228                                     eb + enc_data_len - pad, pad);
00229                         os_free(eb);
00230                         return NULL;
00231                 }
00232         }
00233 
00234         wpa_hexdump_key(MSG_MSGDUMP, "PKCS #5: message M (encrypted key)",
00235                         eb, enc_data_len - pad);
00236 
00237         *data_len = enc_data_len - pad;
00238         return eb;
00239 }
00240 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines

Generated on Sat Nov 21 23:16:53 2009 for hostapd by  doxygen 1.6.1