Android build: fix usage of NDK home variable ($ndk_var)
[openssl.git] / crypto / dh / dh_kdf.c
1 /*
2  * Copyright 2013-2016 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the OpenSSL license (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9
10 #include "e_os.h"
11
12 #ifndef OPENSSL_NO_CMS
13 #include <string.h>
14 #include <openssl/dh.h>
15 #include <openssl/evp.h>
16 #include <openssl/asn1.h>
17 #include <openssl/cms.h>
18
19
20 /* Key derivation from X9.42/RFC2631 */
21 /* Uses CMS functions, hence the #ifdef wrapper. */
22
23 #define DH_KDF_MAX      (1L << 30)
24
25 /* Skip past an ASN1 structure: for OBJECT skip content octets too */
26
27 static int skip_asn1(unsigned char **pp, long *plen, int exptag)
28 {
29     const unsigned char *q = *pp;
30     int i, tag, xclass;
31     long tmplen;
32     i = ASN1_get_object(&q, &tmplen, &tag, &xclass, *plen);
33     if (i & 0x80)
34         return 0;
35     if (tag != exptag || xclass != V_ASN1_UNIVERSAL)
36         return 0;
37     if (tag == V_ASN1_OBJECT)
38         q += tmplen;
39     *plen -= q - *pp;
40     *pp = (unsigned char *)q;
41     return 1;
42 }
43
44 /*
45  * Encode the DH shared info structure, return an offset to the counter value
46  * so we can update the structure without reencoding it.
47  */
48
49 static int dh_sharedinfo_encode(unsigned char **pder, unsigned char **pctr,
50                                 ASN1_OBJECT *key_oid, size_t outlen,
51                                 const unsigned char *ukm, size_t ukmlen)
52 {
53     unsigned char *p;
54     int derlen;
55     long tlen;
56     /* "magic" value to check offset is sane */
57     static unsigned char ctr[4] = { 0xF3, 0x17, 0x22, 0x53 };
58     X509_ALGOR atmp;
59     ASN1_OCTET_STRING ctr_oct, ukm_oct, *pukm_oct;
60     ASN1_TYPE ctr_atype;
61     if (ukmlen > DH_KDF_MAX || outlen > DH_KDF_MAX)
62         return 0;
63     ctr_oct.data = ctr;
64     ctr_oct.length = 4;
65     ctr_oct.flags = 0;
66     ctr_oct.type = V_ASN1_OCTET_STRING;
67     ctr_atype.type = V_ASN1_OCTET_STRING;
68     ctr_atype.value.octet_string = &ctr_oct;
69     atmp.algorithm = key_oid;
70     atmp.parameter = &ctr_atype;
71     if (ukm) {
72         ukm_oct.type = V_ASN1_OCTET_STRING;
73         ukm_oct.flags = 0;
74         ukm_oct.data = (unsigned char *)ukm;
75         ukm_oct.length = ukmlen;
76         pukm_oct = &ukm_oct;
77     } else
78         pukm_oct = NULL;
79     derlen = CMS_SharedInfo_encode(pder, &atmp, pukm_oct, outlen);
80     if (derlen <= 0)
81         return 0;
82     p = *pder;
83     tlen = derlen;
84     if (!skip_asn1(&p, &tlen, V_ASN1_SEQUENCE))
85         return 0;
86     if (!skip_asn1(&p, &tlen, V_ASN1_SEQUENCE))
87         return 0;
88     if (!skip_asn1(&p, &tlen, V_ASN1_OBJECT))
89         return 0;
90     if (!skip_asn1(&p, &tlen, V_ASN1_OCTET_STRING))
91         return 0;
92     if (CRYPTO_memcmp(p, ctr, 4))
93         return 0;
94     *pctr = p;
95     return derlen;
96 }
97
98 int DH_KDF_X9_42(unsigned char *out, size_t outlen,
99                  const unsigned char *Z, size_t Zlen,
100                  ASN1_OBJECT *key_oid,
101                  const unsigned char *ukm, size_t ukmlen, const EVP_MD *md)
102 {
103     EVP_MD_CTX *mctx = NULL;
104     int rv = 0;
105     unsigned int i;
106     size_t mdlen;
107     unsigned char *der = NULL, *ctr;
108     int derlen;
109     if (Zlen > DH_KDF_MAX)
110         return 0;
111     mctx = EVP_MD_CTX_new();
112     if (mctx == NULL)
113         return 0;
114     mdlen = EVP_MD_size(md);
115     derlen = dh_sharedinfo_encode(&der, &ctr, key_oid, outlen, ukm, ukmlen);
116     if (derlen == 0)
117         goto err;
118     for (i = 1;; i++) {
119         unsigned char mtmp[EVP_MAX_MD_SIZE];
120         if (!EVP_DigestInit_ex(mctx, md, NULL)
121             || !EVP_DigestUpdate(mctx, Z, Zlen))
122             goto err;
123         ctr[3] = i & 0xFF;
124         ctr[2] = (i >> 8) & 0xFF;
125         ctr[1] = (i >> 16) & 0xFF;
126         ctr[0] = (i >> 24) & 0xFF;
127         if (!EVP_DigestUpdate(mctx, der, derlen))
128             goto err;
129         if (outlen >= mdlen) {
130             if (!EVP_DigestFinal(mctx, out, NULL))
131                 goto err;
132             outlen -= mdlen;
133             if (outlen == 0)
134                 break;
135             out += mdlen;
136         } else {
137             if (!EVP_DigestFinal(mctx, mtmp, NULL))
138                 goto err;
139             memcpy(out, mtmp, outlen);
140             OPENSSL_cleanse(mtmp, mdlen);
141             break;
142         }
143     }
144     rv = 1;
145  err:
146     OPENSSL_free(der);
147     EVP_MD_CTX_free(mctx);
148     return rv;
149 }
150 #endif