OpenCoverage

cms_pwri.c

Absolute File Name:/home/opencoverage/opencoverage/guest-scripts/openssl/src/crypto/cms/cms_pwri.c
Source codeSwitch to Preprocessed file
LineSourceCount
1/*-
2 * Copyright 2009-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/pem.h>-
13#include <openssl/x509v3.h>-
14#include <openssl/err.h>-
15#include <openssl/cms.h>-
16#include <openssl/rand.h>-
17#include <openssl/aes.h>-
18#include "cms_lcl.h"-
19#include "internal/asn1_int.h"-
20-
21int CMS_RecipientInfo_set0_password(CMS_RecipientInfo *ri,-
22 unsigned char *pass, ossl_ssize_t passlen)-
23{-
24 CMS_PasswordRecipientInfo *pwri;-
25 if (ri->type != CMS_RECIPINFO_PASS) {
ri->type != 3Description
TRUEnever evaluated
FALSEnever evaluated
0
26 CMSerr(CMS_F_CMS_RECIPIENTINFO_SET0_PASSWORD, CMS_R_NOT_PWRI);-
27 return 0;
never executed: return 0;
0
28 }-
29-
30 pwri = ri->d.pwri;-
31 pwri->pass = pass;-
32 if (pass && passlen < 0)
passDescription
TRUEnever evaluated
FALSEnever evaluated
passlen < 0Description
TRUEnever evaluated
FALSEnever evaluated
0
33 passlen = strlen((char *)pass);
never executed: passlen = strlen((char *)pass);
0
34 pwri->passlen = passlen;-
35 return 1;
never executed: return 1;
0
36}-
37-
38CMS_RecipientInfo *CMS_add0_recipient_password(CMS_ContentInfo *cms,-
39 int iter, int wrap_nid,-
40 int pbe_nid,-
41 unsigned char *pass,-
42 ossl_ssize_t passlen,-
43 const EVP_CIPHER *kekciph)-
44{-
45 CMS_RecipientInfo *ri = NULL;-
46 CMS_EnvelopedData *env;-
47 CMS_PasswordRecipientInfo *pwri;-
48 EVP_CIPHER_CTX *ctx = NULL;-
49 X509_ALGOR *encalg = NULL;-
50 unsigned char iv[EVP_MAX_IV_LENGTH];-
51 int ivlen;-
52-
53 env = cms_get0_enveloped(cms);-
54 if (!env)
!envDescription
TRUEnever evaluated
FALSEnever evaluated
0
55 return NULL;
never executed: return ((void *)0) ;
0
56-
57 if (wrap_nid <= 0)
wrap_nid <= 0Description
TRUEnever evaluated
FALSEnever evaluated
0
58 wrap_nid = NID_id_alg_PWRI_KEK;
never executed: wrap_nid = 893;
0
59-
60 if (pbe_nid <= 0)
pbe_nid <= 0Description
TRUEnever evaluated
FALSEnever evaluated
0
61 pbe_nid = NID_id_pbkdf2;
never executed: pbe_nid = 69;
0
62-
63 /* Get from enveloped data */-
64 if (kekciph == NULL)
kekciph == ((void *)0)Description
TRUEnever evaluated
FALSEnever evaluated
0
65 kekciph = env->encryptedContentInfo->cipher;
never executed: kekciph = env->encryptedContentInfo->cipher;
0
66-
67 if (kekciph == NULL) {
kekciph == ((void *)0)Description
TRUEnever evaluated
FALSEnever evaluated
0
68 CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD, CMS_R_NO_CIPHER);-
69 return NULL;
never executed: return ((void *)0) ;
0
70 }-
71 if (wrap_nid != NID_id_alg_PWRI_KEK) {
wrap_nid != 893Description
TRUEnever evaluated
FALSEnever evaluated
0
72 CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD,-
73 CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM);-
74 return NULL;
never executed: return ((void *)0) ;
0
75 }-
76-
77 /* Setup algorithm identifier for cipher */-
78 encalg = X509_ALGOR_new();-
79 if (encalg == NULL) {
encalg == ((void *)0)Description
TRUEnever evaluated
FALSEnever evaluated
0
80 goto merr;
never executed: goto merr;
0
81 }-
82 ctx = EVP_CIPHER_CTX_new();-
83-
84 if (EVP_EncryptInit_ex(ctx, kekciph, NULL, NULL, NULL) <= 0) {
EVP_EncryptIni...id *)0) ) <= 0Description
TRUEnever evaluated
FALSEnever evaluated
0
85 CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD, ERR_R_EVP_LIB);-
86 goto err;
never executed: goto err;
0
87 }-
88-
89 ivlen = EVP_CIPHER_CTX_iv_length(ctx);-
90-
91 if (ivlen > 0) {
ivlen > 0Description
TRUEnever evaluated
FALSEnever evaluated
0
92 if (RAND_bytes(iv, ivlen) <= 0)
RAND_bytes(iv, ivlen) <= 0Description
TRUEnever evaluated
FALSEnever evaluated
0
93 goto err;
never executed: goto err;
0
94 if (EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, iv) <= 0) {
EVP_EncryptIni...)0) , iv) <= 0Description
TRUEnever evaluated
FALSEnever evaluated
0
95 CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD, ERR_R_EVP_LIB);-
96 goto err;
never executed: goto err;
0
97 }-
98 encalg->parameter = ASN1_TYPE_new();-
99 if (!encalg->parameter) {
!encalg->parameterDescription
TRUEnever evaluated
FALSEnever evaluated
0
100 CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD, ERR_R_MALLOC_FAILURE);-
101 goto err;
never executed: goto err;
0
102 }-
103 if (EVP_CIPHER_param_to_asn1(ctx, encalg->parameter) <= 0) {
EVP_CIPHER_par...arameter) <= 0Description
TRUEnever evaluated
FALSEnever evaluated
0
104 CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD,-
105 CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR);-
106 goto err;
never executed: goto err;
0
107 }-
108 }
never executed: end of block
0
109-
110 encalg->algorithm = OBJ_nid2obj(EVP_CIPHER_CTX_type(ctx));-
111-
112 EVP_CIPHER_CTX_free(ctx);-
113 ctx = NULL;-
114-
115 /* Initialize recipient info */-
116 ri = M_ASN1_new_of(CMS_RecipientInfo);-
117 if (ri == NULL)
ri == ((void *)0)Description
TRUEnever evaluated
FALSEnever evaluated
0
118 goto merr;
never executed: goto merr;
0
119-
120 ri->d.pwri = M_ASN1_new_of(CMS_PasswordRecipientInfo);-
121 if (ri->d.pwri == NULL)
ri->d.pwri == ((void *)0)Description
TRUEnever evaluated
FALSEnever evaluated
0
122 goto merr;
never executed: goto merr;
0
123 ri->type = CMS_RECIPINFO_PASS;-
124-
125 pwri = ri->d.pwri;-
126 /* Since this is overwritten, free up empty structure already there */-
127 X509_ALGOR_free(pwri->keyEncryptionAlgorithm);-
128 pwri->keyEncryptionAlgorithm = X509_ALGOR_new();-
129 if (pwri->keyEncryptionAlgorithm == NULL)
pwri->keyEncry...== ((void *)0)Description
TRUEnever evaluated
FALSEnever evaluated
0
130 goto merr;
never executed: goto merr;
0
131 pwri->keyEncryptionAlgorithm->algorithm = OBJ_nid2obj(wrap_nid);-
132 pwri->keyEncryptionAlgorithm->parameter = ASN1_TYPE_new();-
133 if (pwri->keyEncryptionAlgorithm->parameter == NULL)
pwri->keyEncry...== ((void *)0)Description
TRUEnever evaluated
FALSEnever evaluated
0
134 goto merr;
never executed: goto merr;
0
135-
136 if (!ASN1_item_pack(encalg, ASN1_ITEM_rptr(X509_ALGOR),
!ASN1_item_pac...alue.sequence)Description
TRUEnever evaluated
FALSEnever evaluated
0
137 &pwri->keyEncryptionAlgorithm->parameter->
!ASN1_item_pac...alue.sequence)Description
TRUEnever evaluated
FALSEnever evaluated
0
138 value.sequence))
!ASN1_item_pac...alue.sequence)Description
TRUEnever evaluated
FALSEnever evaluated
0
139 goto merr;
never executed: goto merr;
0
140 pwri->keyEncryptionAlgorithm->parameter->type = V_ASN1_SEQUENCE;-
141-
142 X509_ALGOR_free(encalg);-
143 encalg = NULL;-
144-
145 /* Setup PBE algorithm */-
146-
147 pwri->keyDerivationAlgorithm = PKCS5_pbkdf2_set(iter, NULL, 0, -1, -1);-
148-
149 if (!pwri->keyDerivationAlgorithm)
!pwri->keyDerivationAlgorithmDescription
TRUEnever evaluated
FALSEnever evaluated
0
150 goto err;
never executed: goto err;
0
151-
152 CMS_RecipientInfo_set0_password(ri, pass, passlen);-
153 pwri->version = 0;-
154-
155 if (!sk_CMS_RecipientInfo_push(env->recipientInfos, ri))
!sk_CMS_Recipi...ientInfos, ri)Description
TRUEnever evaluated
FALSEnever evaluated
0
156 goto merr;
never executed: goto merr;
0
157-
158 return ri;
never executed: return ri;
0
159-
160 merr:-
161 CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD, ERR_R_MALLOC_FAILURE);-
162 err:
code before this statement never executed: err:
0
163 EVP_CIPHER_CTX_free(ctx);-
164 if (ri)
riDescription
TRUEnever evaluated
FALSEnever evaluated
0
165 M_ASN1_free_of(ri, CMS_RecipientInfo);
never executed: ASN1_item_free(((void*) (1 ? ri : (CMS_RecipientInfo*)0)), (&(CMS_RecipientInfo_it)));
0
166 X509_ALGOR_free(encalg);-
167 return NULL;
never executed: return ((void *)0) ;
0
168-
169}-
170-
171/*-
172 * This is an implementation of the key wrapping mechanism in RFC3211, at-
173 * some point this should go into EVP.-
174 */-
175-
176static int kek_unwrap_key(unsigned char *out, size_t *outlen,-
177 const unsigned char *in, size_t inlen,-
178 EVP_CIPHER_CTX *ctx)-
179{-
180 size_t blocklen = EVP_CIPHER_CTX_block_size(ctx);-
181 unsigned char *tmp;-
182 int outl, rv = 0;-
183 if (inlen < 2 * blocklen) {
inlen < 2 * blocklenDescription
TRUEnever evaluated
FALSEnever evaluated
0
184 /* too small */-
185 return 0;
never executed: return 0;
0
186 }-
187 if (inlen % blocklen) {
inlen % blocklenDescription
TRUEnever evaluated
FALSEnever evaluated
0
188 /* Invalid size */-
189 return 0;
never executed: return 0;
0
190 }-
191 if ((tmp = OPENSSL_malloc(inlen)) == NULL) {
(tmp = CRYPTO_...== ((void *)0)Description
TRUEnever evaluated
FALSEnever evaluated
0
192 CMSerr(CMS_F_KEK_UNWRAP_KEY, ERR_R_MALLOC_FAILURE);-
193 return 0;
never executed: return 0;
0
194 }-
195 /* setup IV by decrypting last two blocks */-
196 if (!EVP_DecryptUpdate(ctx, tmp + inlen - 2 * blocklen, &outl,
!EVP_DecryptUp... blocklen * 2)Description
TRUEnever evaluated
FALSEnever evaluated
0
197 in + inlen - 2 * blocklen, blocklen * 2)
!EVP_DecryptUp... blocklen * 2)Description
TRUEnever evaluated
FALSEnever evaluated
0
198 /*-
199 * Do a decrypt of last decrypted block to set IV to correct value-
200 * output it to start of buffer so we don't corrupt decrypted block-
201 * this works because buffer is at least two block lengths long.-
202 */-
203 || !EVP_DecryptUpdate(ctx, tmp, &outl,
!EVP_DecryptUp...len, blocklen)Description
TRUEnever evaluated
FALSEnever evaluated
0
204 tmp + inlen - blocklen, blocklen)
!EVP_DecryptUp...len, blocklen)Description
TRUEnever evaluated
FALSEnever evaluated
0
205 /* Can now decrypt first n - 1 blocks */-
206 || !EVP_DecryptUpdate(ctx, tmp, &outl, in, inlen - blocklen)
!EVP_DecryptUp...en - blocklen)Description
TRUEnever evaluated
FALSEnever evaluated
0
207-
208 /* Reset IV to original value */-
209 || !EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, NULL)
!EVP_DecryptIn... ((void *)0) )Description
TRUEnever evaluated
FALSEnever evaluated
0
210 /* Decrypt again */-
211 || !EVP_DecryptUpdate(ctx, tmp, &outl, tmp, inlen))
!EVP_DecryptUp...l, tmp, inlen)Description
TRUEnever evaluated
FALSEnever evaluated
0
212 goto err;
never executed: goto err;
0
213 /* Check check bytes */-
214 if (((tmp[1] ^ tmp[4]) & (tmp[2] ^ tmp[5]) & (tmp[3] ^ tmp[6])) != 0xff) {
((tmp[1] ^ tmp...p[6])) != 0xffDescription
TRUEnever evaluated
FALSEnever evaluated
0
215 /* Check byte failure */-
216 goto err;
never executed: goto err;
0
217 }-
218 if (inlen < (size_t)(tmp[0] - 4)) {
inlen < (size_t)(tmp[0] - 4)Description
TRUEnever evaluated
FALSEnever evaluated
0
219 /* Invalid length value */-
220 goto err;
never executed: goto err;
0
221 }-
222 *outlen = (size_t)tmp[0];-
223 memcpy(out, tmp + 4, *outlen);-
224 rv = 1;-
225 err:
code before this statement never executed: err:
0
226 OPENSSL_clear_free(tmp, inlen);-
227 return rv;
never executed: return rv;
0
228-
229}-
230-
231static int kek_wrap_key(unsigned char *out, size_t *outlen,-
232 const unsigned char *in, size_t inlen,-
233 EVP_CIPHER_CTX *ctx)-
234{-
235 size_t blocklen = EVP_CIPHER_CTX_block_size(ctx);-
236 size_t olen;-
237 int dummy;-
238 /*-
239 * First decide length of output buffer: need header and round up to-
240 * multiple of block length.-
241 */-
242 olen = (inlen + 4 + blocklen - 1) / blocklen;-
243 olen *= blocklen;-
244 if (olen < 2 * blocklen) {
olen < 2 * blocklenDescription
TRUEnever evaluated
FALSEnever evaluated
0
245 /* Key too small */-
246 return 0;
never executed: return 0;
0
247 }-
248 if (inlen > 0xFF) {
inlen > 0xFFDescription
TRUEnever evaluated
FALSEnever evaluated
0
249 /* Key too large */-
250 return 0;
never executed: return 0;
0
251 }-
252 if (out) {
outDescription
TRUEnever evaluated
FALSEnever evaluated
0
253 /* Set header */-
254 out[0] = (unsigned char)inlen;-
255 out[1] = in[0] ^ 0xFF;-
256 out[2] = in[1] ^ 0xFF;-
257 out[3] = in[2] ^ 0xFF;-
258 memcpy(out + 4, in, inlen);-
259 /* Add random padding to end */-
260 if (olen > inlen + 4
olen > inlen + 4Description
TRUEnever evaluated
FALSEnever evaluated
0
261 && RAND_bytes(out + 4 + inlen, olen - 4 - inlen) <= 0)
RAND_bytes(out... - inlen) <= 0Description
TRUEnever evaluated
FALSEnever evaluated
0
262 return 0;
never executed: return 0;
0
263 /* Encrypt twice */-
264 if (!EVP_EncryptUpdate(ctx, out, &dummy, out, olen)
!EVP_EncryptUp...my, out, olen)Description
TRUEnever evaluated
FALSEnever evaluated
0
265 || !EVP_EncryptUpdate(ctx, out, &dummy, out, olen))
!EVP_EncryptUp...my, out, olen)Description
TRUEnever evaluated
FALSEnever evaluated
0
266 return 0;
never executed: return 0;
0
267 }
never executed: end of block
0
268-
269 *outlen = olen;-
270-
271 return 1;
never executed: return 1;
0
272}-
273-
274/* Encrypt/Decrypt content key in PWRI recipient info */-
275-
276int cms_RecipientInfo_pwri_crypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri,-
277 int en_de)-
278{-
279 CMS_EncryptedContentInfo *ec;-
280 CMS_PasswordRecipientInfo *pwri;-
281 int r = 0;-
282 X509_ALGOR *algtmp, *kekalg = NULL;-
283 EVP_CIPHER_CTX *kekctx = NULL;-
284 const EVP_CIPHER *kekcipher;-
285 unsigned char *key = NULL;-
286 size_t keylen;-
287-
288 ec = cms->d.envelopedData->encryptedContentInfo;-
289-
290 pwri = ri->d.pwri;-
291-
292 if (!pwri->pass) {
!pwri->passDescription
TRUEnever evaluated
FALSEnever evaluated
0
293 CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT, CMS_R_NO_PASSWORD);-
294 return 0;
never executed: return 0;
0
295 }-
296 algtmp = pwri->keyEncryptionAlgorithm;-
297-
298 if (!algtmp || OBJ_obj2nid(algtmp->algorithm) != NID_id_alg_PWRI_KEK) {
!algtmpDescription
TRUEnever evaluated
FALSEnever evaluated
OBJ_obj2nid(al...orithm) != 893Description
TRUEnever evaluated
FALSEnever evaluated
0
299 CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT,-
300 CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM);-
301 return 0;
never executed: return 0;
0
302 }-
303-
304 kekalg = ASN1_TYPE_unpack_sequence(ASN1_ITEM_rptr(X509_ALGOR),-
305 algtmp->parameter);-
306-
307 if (kekalg == NULL) {
kekalg == ((void *)0)Description
TRUEnever evaluated
FALSEnever evaluated
0
308 CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT,-
309 CMS_R_INVALID_KEY_ENCRYPTION_PARAMETER);-
310 return 0;
never executed: return 0;
0
311 }-
312-
313 kekcipher = EVP_get_cipherbyobj(kekalg->algorithm);-
314-
315 if (!kekcipher) {
!kekcipherDescription
TRUEnever evaluated
FALSEnever evaluated
0
316 CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT, CMS_R_UNKNOWN_CIPHER);-
317 return 0;
never executed: return 0;
0
318 }-
319-
320 kekctx = EVP_CIPHER_CTX_new();-
321 if (kekctx == NULL) {
kekctx == ((void *)0)Description
TRUEnever evaluated
FALSEnever evaluated
0
322 CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT, ERR_R_MALLOC_FAILURE);-
323 return 0;
never executed: return 0;
0
324 }-
325 /* Fixup cipher based on AlgorithmIdentifier to set IV etc */-
326 if (!EVP_CipherInit_ex(kekctx, kekcipher, NULL, NULL, NULL, en_de))
!EVP_CipherIni... *)0) , en_de)Description
TRUEnever evaluated
FALSEnever evaluated
0
327 goto err;
never executed: goto err;
0
328 EVP_CIPHER_CTX_set_padding(kekctx, 0);-
329 if (EVP_CIPHER_asn1_to_param(kekctx, kekalg->parameter) <= 0) {
EVP_CIPHER_asn...arameter) <= 0Description
TRUEnever evaluated
FALSEnever evaluated
0
330 CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT,-
331 CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR);-
332 goto err;
never executed: goto err;
0
333 }-
334-
335 algtmp = pwri->keyDerivationAlgorithm;-
336-
337 /* Finish password based key derivation to setup key in "ctx" */-
338-
339 if (EVP_PBE_CipherInit(algtmp->algorithm,
EVP_PBE_Cipher...tx, en_de) < 0Description
TRUEnever evaluated
FALSEnever evaluated
0
340 (char *)pwri->pass, pwri->passlen,
EVP_PBE_Cipher...tx, en_de) < 0Description
TRUEnever evaluated
FALSEnever evaluated
0
341 algtmp->parameter, kekctx, en_de) < 0) {
EVP_PBE_Cipher...tx, en_de) < 0Description
TRUEnever evaluated
FALSEnever evaluated
0
342 CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT, ERR_R_EVP_LIB);-
343 goto err;
never executed: goto err;
0
344 }-
345-
346 /* Finally wrap/unwrap the key */-
347-
348 if (en_de) {
en_deDescription
TRUEnever evaluated
FALSEnever evaluated
0
349-
350 if (!kek_wrap_key(NULL, &keylen, ec->key, ec->keylen, kekctx))
!kek_wrap_key(...eylen, kekctx)Description
TRUEnever evaluated
FALSEnever evaluated
0
351 goto err;
never executed: goto err;
0
352-
353 key = OPENSSL_malloc(keylen);-
354-
355 if (key == NULL)
key == ((void *)0)Description
TRUEnever evaluated
FALSEnever evaluated
0
356 goto err;
never executed: goto err;
0
357-
358 if (!kek_wrap_key(key, &keylen, ec->key, ec->keylen, kekctx))
!kek_wrap_key(...eylen, kekctx)Description
TRUEnever evaluated
FALSEnever evaluated
0
359 goto err;
never executed: goto err;
0
360 pwri->encryptedKey->data = key;-
361 pwri->encryptedKey->length = keylen;-
362 } else {
never executed: end of block
0
363 key = OPENSSL_malloc(pwri->encryptedKey->length);-
364-
365 if (key == NULL) {
key == ((void *)0)Description
TRUEnever evaluated
FALSEnever evaluated
0
366 CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT, ERR_R_MALLOC_FAILURE);-
367 goto err;
never executed: goto err;
0
368 }-
369 if (!kek_unwrap_key(key, &keylen,
!kek_unwrap_ke...ength, kekctx)Description
TRUEnever evaluated
FALSEnever evaluated
0
370 pwri->encryptedKey->data,
!kek_unwrap_ke...ength, kekctx)Description
TRUEnever evaluated
FALSEnever evaluated
0
371 pwri->encryptedKey->length, kekctx)) {
!kek_unwrap_ke...ength, kekctx)Description
TRUEnever evaluated
FALSEnever evaluated
0
372 CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT, CMS_R_UNWRAP_FAILURE);-
373 goto err;
never executed: goto err;
0
374 }-
375-
376 ec->key = key;-
377 ec->keylen = keylen;-
378-
379 }
never executed: end of block
0
380-
381 r = 1;-
382-
383 err:
code before this statement never executed: err:
0
384-
385 EVP_CIPHER_CTX_free(kekctx);-
386-
387 if (!r)
!rDescription
TRUEnever evaluated
FALSEnever evaluated
0
388 OPENSSL_free(key);
never executed: CRYPTO_free(key, __FILE__, 388);
0
389 X509_ALGOR_free(kekalg);-
390-
391 return r;
never executed: return r;
0
392-
393}-
Source codeSwitch to Preprocessed file

Generated by Squish Coco 4.2.2