OpenCoverage

sm2_pmeth.c

Absolute File Name:/home/opencoverage/opencoverage/guest-scripts/openssl/src/crypto/sm2/sm2_pmeth.c
Source codeSwitch to Preprocessed file
LineSourceCount
1/*-
2 * Copyright 2006-2018 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 "internal/cryptlib.h"-
11#include <openssl/asn1t.h>-
12#include <openssl/ec.h>-
13#include <openssl/evp.h>-
14#include "internal/evp_int.h"-
15#include "internal/sm2.h"-
16#include "internal/sm2err.h"-
17-
18/* EC pkey context structure */-
19-
20typedef struct {-
21 /* Key and paramgen group */-
22 EC_GROUP *gen_group;-
23 /* message digest */-
24 const EVP_MD *md;-
25 /* Distinguishing Identifier, ISO/IEC 15946-3 */-
26 uint8_t *id;-
27 size_t id_len;-
28 /* id_set indicates if the 'id' field is set (1) or not (0) */-
29 int id_set;-
30} SM2_PKEY_CTX;-
31-
32static int pkey_sm2_init(EVP_PKEY_CTX *ctx)-
33{-
34 SM2_PKEY_CTX *smctx;-
35-
36 if ((smctx = OPENSSL_zalloc(sizeof(*smctx))) == NULL) {
(smctx = CRYPT...== ((void *)0)Description
TRUEnever evaluated
FALSEevaluated 11 times by 1 test
Evaluated by:
  • libcrypto.so.1.1
0-11
37 SM2err(SM2_F_PKEY_SM2_INIT, ERR_R_MALLOC_FAILURE);-
38 return 0;
never executed: return 0;
0
39 }-
40-
41 ctx->data = smctx;-
42 return 1;
executed 11 times by 1 test: return 1;
Executed by:
  • libcrypto.so.1.1
11
43}-
44-
45static void pkey_sm2_cleanup(EVP_PKEY_CTX *ctx)-
46{-
47 SM2_PKEY_CTX *smctx = ctx->data;-
48-
49 if (smctx != NULL) {
smctx != ((void *)0)Description
TRUEevaluated 11 times by 1 test
Evaluated by:
  • libcrypto.so.1.1
FALSEnever evaluated
0-11
50 EC_GROUP_free(smctx->gen_group);-
51 OPENSSL_free(smctx->id);-
52 OPENSSL_free(smctx);-
53 ctx->data = NULL;-
54 }
executed 11 times by 1 test: end of block
Executed by:
  • libcrypto.so.1.1
11
55}
executed 11 times by 1 test: end of block
Executed by:
  • libcrypto.so.1.1
11
56-
57static int pkey_sm2_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src)-
58{-
59 SM2_PKEY_CTX *dctx, *sctx;-
60-
61 if (!pkey_sm2_init(dst))
!pkey_sm2_init(dst)Description
TRUEnever evaluated
FALSEevaluated 3 times by 1 test
Evaluated by:
  • libcrypto.so.1.1
0-3
62 return 0;
never executed: return 0;
0
63 sctx = src->data;-
64 dctx = dst->data;-
65 if (sctx->gen_group != NULL) {
sctx->gen_group != ((void *)0)Description
TRUEnever evaluated
FALSEevaluated 3 times by 1 test
Evaluated by:
  • libcrypto.so.1.1
0-3
66 dctx->gen_group = EC_GROUP_dup(sctx->gen_group);-
67 if (dctx->gen_group == NULL) {
dctx->gen_group == ((void *)0)Description
TRUEnever evaluated
FALSEnever evaluated
0
68 pkey_sm2_cleanup(dst);-
69 return 0;
never executed: return 0;
0
70 }-
71 }
never executed: end of block
0
72 if (sctx->id != NULL) {
sctx->id != ((void *)0)Description
TRUEevaluated 3 times by 1 test
Evaluated by:
  • libcrypto.so.1.1
FALSEnever evaluated
0-3
73 dctx->id = OPENSSL_malloc(sctx->id_len);-
74 if (dctx->id == NULL) {
dctx->id == ((void *)0)Description
TRUEnever evaluated
FALSEevaluated 3 times by 1 test
Evaluated by:
  • libcrypto.so.1.1
0-3
75 SM2err(SM2_F_PKEY_SM2_COPY, ERR_R_MALLOC_FAILURE);-
76 pkey_sm2_cleanup(dst);-
77 return 0;
never executed: return 0;
0
78 }-
79 memcpy(dctx->id, sctx->id, sctx->id_len);-
80 }
executed 3 times by 1 test: end of block
Executed by:
  • libcrypto.so.1.1
3
81 dctx->id_len = sctx->id_len;-
82 dctx->id_set = sctx->id_set;-
83 dctx->md = sctx->md;-
84-
85 return 1;
executed 3 times by 1 test: return 1;
Executed by:
  • libcrypto.so.1.1
3
86}-
87-
88static int pkey_sm2_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,-
89 const unsigned char *tbs, size_t tbslen)-
90{-
91 int ret;-
92 unsigned int sltmp;-
93 EC_KEY *ec = ctx->pkey->pkey.ec;-
94 const int sig_sz = ECDSA_size(ctx->pkey->pkey.ec);-
95-
96 if (sig_sz <= 0) {
sig_sz <= 0Description
TRUEnever evaluated
FALSEevaluated 4 times by 1 test
Evaluated by:
  • libcrypto.so.1.1
0-4
97 return 0;
never executed: return 0;
0
98 }-
99-
100 if (sig == NULL) {
sig == ((void *)0)Description
TRUEevaluated 2 times by 1 test
Evaluated by:
  • libcrypto.so.1.1
FALSEevaluated 2 times by 1 test
Evaluated by:
  • libcrypto.so.1.1
2
101 *siglen = (size_t)sig_sz;-
102 return 1;
executed 2 times by 1 test: return 1;
Executed by:
  • libcrypto.so.1.1
2
103 }-
104-
105 if (*siglen < (size_t)sig_sz) {
*siglen < (size_t)sig_szDescription
TRUEnever evaluated
FALSEevaluated 2 times by 1 test
Evaluated by:
  • libcrypto.so.1.1
0-2
106 SM2err(SM2_F_PKEY_SM2_SIGN, SM2_R_BUFFER_TOO_SMALL);-
107 return 0;
never executed: return 0;
0
108 }-
109-
110 ret = sm2_sign(tbs, tbslen, sig, &sltmp, ec);-
111-
112 if (ret <= 0)
ret <= 0Description
TRUEnever evaluated
FALSEevaluated 2 times by 1 test
Evaluated by:
  • libcrypto.so.1.1
0-2
113 return ret;
never executed: return ret;
0
114 *siglen = (size_t)sltmp;-
115 return 1;
executed 2 times by 1 test: return 1;
Executed by:
  • libcrypto.so.1.1
2
116}-
117-
118static int pkey_sm2_verify(EVP_PKEY_CTX *ctx,-
119 const unsigned char *sig, size_t siglen,-
120 const unsigned char *tbs, size_t tbslen)-
121{-
122 EC_KEY *ec = ctx->pkey->pkey.ec;-
123-
124 return sm2_verify(tbs, tbslen, sig, siglen, ec);
executed 5 times by 1 test: return sm2_verify(tbs, tbslen, sig, siglen, ec);
Executed by:
  • libcrypto.so.1.1
5
125}-
126-
127static int pkey_sm2_encrypt(EVP_PKEY_CTX *ctx,-
128 unsigned char *out, size_t *outlen,-
129 const unsigned char *in, size_t inlen)-
130{-
131 EC_KEY *ec = ctx->pkey->pkey.ec;-
132 SM2_PKEY_CTX *dctx = ctx->data;-
133 const EVP_MD *md = (dctx->md == NULL) ? EVP_sm3() : dctx->md;
(dctx->md == ((void *)0) )Description
TRUEevaluated 1 time by 1 test
Evaluated by:
  • libcrypto.so.1.1
FALSEnever evaluated
0-1
134-
135 if (out == NULL) {
out == ((void *)0)Description
TRUEnever evaluated
FALSEevaluated 1 time by 1 test
Evaluated by:
  • libcrypto.so.1.1
0-1
136 if (!sm2_ciphertext_size(ec, md, inlen, outlen))
!sm2_ciphertex...inlen, outlen)Description
TRUEnever evaluated
FALSEnever evaluated
0
137 return -1;
never executed: return -1;
0
138 else-
139 return 1;
never executed: return 1;
0
140 }-
141-
142 return sm2_encrypt(ec, md, in, inlen, out, outlen);
executed 1 time by 1 test: return sm2_encrypt(ec, md, in, inlen, out, outlen);
Executed by:
  • libcrypto.so.1.1
1
143}-
144-
145static int pkey_sm2_decrypt(EVP_PKEY_CTX *ctx,-
146 unsigned char *out, size_t *outlen,-
147 const unsigned char *in, size_t inlen)-
148{-
149 EC_KEY *ec = ctx->pkey->pkey.ec;-
150 SM2_PKEY_CTX *dctx = ctx->data;-
151 const EVP_MD *md = (dctx->md == NULL) ? EVP_sm3() : dctx->md;
(dctx->md == ((void *)0) )Description
TRUEevaluated 3 times by 1 test
Evaluated by:
  • libcrypto.so.1.1
FALSEnever evaluated
0-3
152-
153 if (out == NULL) {
out == ((void *)0)Description
TRUEevaluated 1 time by 1 test
Evaluated by:
  • libcrypto.so.1.1
FALSEevaluated 2 times by 1 test
Evaluated by:
  • libcrypto.so.1.1
1-2
154 if (!sm2_plaintext_size(ec, md, inlen, outlen))
!sm2_plaintext...inlen, outlen)Description
TRUEnever evaluated
FALSEevaluated 1 time by 1 test
Evaluated by:
  • libcrypto.so.1.1
0-1
155 return -1;
never executed: return -1;
0
156 else-
157 return 1;
executed 1 time by 1 test: return 1;
Executed by:
  • libcrypto.so.1.1
1
158 }-
159-
160 return sm2_decrypt(ec, md, in, inlen, out, outlen);
executed 2 times by 1 test: return sm2_decrypt(ec, md, in, inlen, out, outlen);
Executed by:
  • libcrypto.so.1.1
2
161}-
162-
163static int pkey_sm2_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)-
164{-
165 SM2_PKEY_CTX *smctx = ctx->data;-
166 EC_GROUP *group;-
167 uint8_t *tmp_id;-
168-
169 switch (type) {-
170 case EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID:
never executed: case (0x1000 + 1):
0
171 group = EC_GROUP_new_by_curve_name(p1);-
172 if (group == NULL) {
group == ((void *)0)Description
TRUEnever evaluated
FALSEnever evaluated
0
173 SM2err(SM2_F_PKEY_SM2_CTRL, SM2_R_INVALID_CURVE);-
174 return 0;
never executed: return 0;
0
175 }-
176 EC_GROUP_free(smctx->gen_group);-
177 smctx->gen_group = group;-
178 return 1;
never executed: return 1;
0
179-
180 case EVP_PKEY_CTRL_EC_PARAM_ENC:
never executed: case (0x1000 + 2):
0
181 if (smctx->gen_group == NULL) {
smctx->gen_gro...== ((void *)0)Description
TRUEnever evaluated
FALSEnever evaluated
0
182 SM2err(SM2_F_PKEY_SM2_CTRL, SM2_R_NO_PARAMETERS_SET);-
183 return 0;
never executed: return 0;
0
184 }-
185 EC_GROUP_set_asn1_flag(smctx->gen_group, p1);-
186 return 1;
never executed: return 1;
0
187-
188 case EVP_PKEY_CTRL_MD:
executed 7 times by 1 test: case 1:
Executed by:
  • libcrypto.so.1.1
7
189 smctx->md = p2;-
190 return 1;
executed 7 times by 1 test: return 1;
Executed by:
  • libcrypto.so.1.1
7
191-
192 case EVP_PKEY_CTRL_GET_MD:
never executed: case 13:
0
193 *(const EVP_MD **)p2 = smctx->md;-
194 return 1;
never executed: return 1;
0
195-
196 case EVP_PKEY_CTRL_SET1_ID:
executed 2 times by 1 test: case (0x1000 + 11):
Executed by:
  • libcrypto.so.1.1
2
197 if (p1 > 0) {
p1 > 0Description
TRUEevaluated 2 times by 1 test
Evaluated by:
  • libcrypto.so.1.1
FALSEnever evaluated
0-2
198 tmp_id = OPENSSL_malloc(p1);-
199 if (tmp_id == NULL) {
tmp_id == ((void *)0)Description
TRUEnever evaluated
FALSEevaluated 2 times by 1 test
Evaluated by:
  • libcrypto.so.1.1
0-2
200 SM2err(SM2_F_PKEY_SM2_CTRL, ERR_R_MALLOC_FAILURE);-
201 return 0;
never executed: return 0;
0
202 }-
203 memcpy(tmp_id, p2, p1);-
204 OPENSSL_free(smctx->id);-
205 smctx->id = tmp_id;-
206 } else {
executed 2 times by 1 test: end of block
Executed by:
  • libcrypto.so.1.1
2
207 /* set null-ID */-
208 OPENSSL_free(smctx->id);-
209 smctx->id = NULL;-
210 }
never executed: end of block
0
211 smctx->id_len = (size_t)p1;-
212 smctx->id_set = 1;-
213 return 1;
executed 2 times by 1 test: return 1;
Executed by:
  • libcrypto.so.1.1
2
214-
215 case EVP_PKEY_CTRL_GET1_ID:
never executed: case (0x1000 + 12):
0
216 memcpy(p2, smctx->id, smctx->id_len);-
217 return 1;
never executed: return 1;
0
218-
219 case EVP_PKEY_CTRL_GET1_ID_LEN:
never executed: case (0x1000 + 13):
0
220 *(size_t *)p2 = smctx->id_len;-
221 return 1;
never executed: return 1;
0
222-
223 default:
executed 3 times by 1 test: default:
Executed by:
  • libcrypto.so.1.1
3
224 return -2;
executed 3 times by 1 test: return -2;
Executed by:
  • libcrypto.so.1.1
3
225 }-
226}-
227-
228static int pkey_sm2_ctrl_str(EVP_PKEY_CTX *ctx,-
229 const char *type, const char *value)-
230{-
231 if (strcmp(type, "ec_paramgen_curve") == 0) {
never executed: __result = (((const unsigned char *) (const char *) ( type ))[3] - __s2[3]);
never executed: end of block
never executed: end of block
never executed: __result = (((const unsigned char *) (const char *) ( "ec_paramgen_curve" ))[3] - __s2[3]);
never executed: end of block
never executed: end of block
__extension__ ... )))); }) == 0Description
TRUEnever evaluated
FALSEnever evaluated
__s1_len > 0Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
__s1_len > 1Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
__s1_len > 2Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
__s2_len > 0Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
__s2_len > 1Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
__s2_len > 2Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
0
232 int nid = NID_undef;-
233-
234 if (((nid = EC_curve_nist2nid(value)) == NID_undef)
((nid = EC_cur...(value)) == 0)Description
TRUEnever evaluated
FALSEnever evaluated
0
235 && ((nid = OBJ_sn2nid(value)) == NID_undef)
((nid = OBJ_sn...(value)) == 0)Description
TRUEnever evaluated
FALSEnever evaluated
0
236 && ((nid = OBJ_ln2nid(value)) == NID_undef)) {
((nid = OBJ_ln...(value)) == 0)Description
TRUEnever evaluated
FALSEnever evaluated
0
237 SM2err(SM2_F_PKEY_SM2_CTRL_STR, SM2_R_INVALID_CURVE);-
238 return 0;
never executed: return 0;
0
239 }-
240 return EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, nid);
never executed: return EVP_PKEY_CTX_ctrl(ctx, 408, (1<<1)|(1<<2), (0x1000 + 1), nid, ((void *)0) );
0
241 } else if (strcmp(type, "ec_param_enc") == 0) {
never executed: __result = (((const unsigned char *) (const char *) ( type ))[3] - __s2[3]);
never executed: end of block
never executed: end of block
never executed: __result = (((const unsigned char *) (const char *) ( "ec_param_enc" ))[3] - __s2[3]);
never executed: end of block
never executed: end of block
__extension__ ... )))); }) == 0Description
TRUEnever evaluated
FALSEnever evaluated
__s1_len > 0Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
__s1_len > 1Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
__s1_len > 2Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
__s2_len > 0Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
__s2_len > 1Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
__s2_len > 2Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
0
242 int param_enc;-
243-
244 if (strcmp(value, "explicit") == 0)
never executed: __result = (((const unsigned char *) (const char *) ( value ))[3] - __s2[3]);
never executed: end of block
never executed: end of block
never executed: __result = (((const unsigned char *) (const char *) ( "explicit" ))[3] - __s2[3]);
never executed: end of block
never executed: end of block
__extension__ ... )))); }) == 0Description
TRUEnever evaluated
FALSEnever evaluated
__s1_len > 0Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
__s1_len > 1Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
__s1_len > 2Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
__s2_len > 0Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
__s2_len > 1Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
__s2_len > 2Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
0
245 param_enc = 0;
never executed: param_enc = 0;
0
246 else if (strcmp(value, "named_curve") == 0)
never executed: __result = (((const unsigned char *) (const char *) ( value ))[3] - __s2[3]);
never executed: end of block
never executed: end of block
never executed: __result = (((const unsigned char *) (const char *) ( "named_curve" ))[3] - __s2[3]);
never executed: end of block
never executed: end of block
__extension__ ... )))); }) == 0Description
TRUEnever evaluated
FALSEnever evaluated
__s1_len > 0Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
__s1_len > 1Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
__s1_len > 2Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
__s2_len > 0Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
__s2_len > 1Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
__s2_len > 2Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
0
247 param_enc = OPENSSL_EC_NAMED_CURVE;
never executed: param_enc = 0x001;
0
248 else-
249 return -2;
never executed: return -2;
0
250 return EVP_PKEY_CTX_set_ec_param_enc(ctx, param_enc);
never executed: return EVP_PKEY_CTX_ctrl(ctx, 408, (1<<1)|(1<<2), (0x1000 + 2), param_enc, ((void *)0) );
0
251 }-
252-
253 return -2;
never executed: return -2;
0
254}-
255-
256static int pkey_sm2_digest_custom(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx)-
257{-
258 uint8_t z[EVP_MAX_MD_SIZE];-
259 SM2_PKEY_CTX *smctx = ctx->data;-
260 EC_KEY *ec = ctx->pkey->pkey.ec;-
261 const EVP_MD *md = EVP_MD_CTX_md(mctx);-
262 int mdlen = EVP_MD_size(md);-
263-
264 if (!smctx->id_set) {
!smctx->id_setDescription
TRUEnever evaluated
FALSEevaluated 3 times by 1 test
Evaluated by:
  • libcrypto.so.1.1
0-3
265 /*-
266 * An ID value must be set. The specifications are not clear whether a-
267 * NULL is allowed. We only allow it if set explicitly for maximum-
268 * flexibility.-
269 */-
270 SM2err(SM2_F_PKEY_SM2_DIGEST_CUSTOM, SM2_R_ID_NOT_SET);-
271 return 0;
never executed: return 0;
0
272 }-
273-
274 if (mdlen < 0) {
mdlen < 0Description
TRUEnever evaluated
FALSEevaluated 3 times by 1 test
Evaluated by:
  • libcrypto.so.1.1
0-3
275 SM2err(SM2_F_PKEY_SM2_DIGEST_CUSTOM, SM2_R_INVALID_DIGEST);-
276 return 0;
never executed: return 0;
0
277 }-
278-
279 /* get hashed prefix 'z' of tbs message */-
280 if (!sm2_compute_z_digest(z, md, smctx->id, smctx->id_len, ec))
!sm2_compute_z...x->id_len, ec)Description
TRUEnever evaluated
FALSEevaluated 3 times by 1 test
Evaluated by:
  • libcrypto.so.1.1
0-3
281 return 0;
never executed: return 0;
0
282-
283 return EVP_DigestUpdate(mctx, z, (size_t)mdlen);
executed 3 times by 1 test: return EVP_DigestUpdate(mctx, z, (size_t)mdlen);
Executed by:
  • libcrypto.so.1.1
3
284}-
285-
286const EVP_PKEY_METHOD sm2_pkey_meth = {-
287 EVP_PKEY_SM2,-
288 0,-
289 pkey_sm2_init,-
290 pkey_sm2_copy,-
291 pkey_sm2_cleanup,-
292-
293 0,-
294 0,-
295-
296 0,-
297 0,-
298-
299 0,-
300 pkey_sm2_sign,-
301-
302 0,-
303 pkey_sm2_verify,-
304-
305 0, 0,-
306-
307 0, 0, 0, 0,-
308-
309 0,-
310 pkey_sm2_encrypt,-
311-
312 0,-
313 pkey_sm2_decrypt,-
314-
315 0,-
316 0,-
317 pkey_sm2_ctrl,-
318 pkey_sm2_ctrl_str,-
319-
320 0, 0,-
321-
322 0, 0, 0,-
323-
324 pkey_sm2_digest_custom-
325};-
Source codeSwitch to Preprocessed file

Generated by Squish Coco 4.2.2