1e1051a39Sopenharmony_ci/* 2e1051a39Sopenharmony_ci * Copyright 2004-2021 The OpenSSL Project Authors. All Rights Reserved. 3e1051a39Sopenharmony_ci * Copyright (c) 2004, EdelKey Project. All Rights Reserved. 4e1051a39Sopenharmony_ci * 5e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License"). You may not use 6e1051a39Sopenharmony_ci * this file except in compliance with the License. You can obtain a copy 7e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at 8e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html 9e1051a39Sopenharmony_ci * 10e1051a39Sopenharmony_ci * Originally written by Christophe Renou and Peter Sylvester, 11e1051a39Sopenharmony_ci * for the EdelKey project. 12e1051a39Sopenharmony_ci */ 13e1051a39Sopenharmony_ci 14e1051a39Sopenharmony_ci/* All the SRP APIs in this file are deprecated */ 15e1051a39Sopenharmony_ci#define OPENSSL_SUPPRESS_DEPRECATED 16e1051a39Sopenharmony_ci 17e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_SRP 18e1051a39Sopenharmony_ci# include "internal/cryptlib.h" 19e1051a39Sopenharmony_ci# include <openssl/sha.h> 20e1051a39Sopenharmony_ci# include <openssl/srp.h> 21e1051a39Sopenharmony_ci# include <openssl/evp.h> 22e1051a39Sopenharmony_ci# include "crypto/bn_srp.h" 23e1051a39Sopenharmony_ci 24e1051a39Sopenharmony_ci/* calculate = SHA1(PAD(x) || PAD(y)) */ 25e1051a39Sopenharmony_ci 26e1051a39Sopenharmony_cistatic BIGNUM *srp_Calc_xy(const BIGNUM *x, const BIGNUM *y, const BIGNUM *N, 27e1051a39Sopenharmony_ci OSSL_LIB_CTX *libctx, const char *propq) 28e1051a39Sopenharmony_ci{ 29e1051a39Sopenharmony_ci unsigned char digest[SHA_DIGEST_LENGTH]; 30e1051a39Sopenharmony_ci unsigned char *tmp = NULL; 31e1051a39Sopenharmony_ci int numN = BN_num_bytes(N); 32e1051a39Sopenharmony_ci BIGNUM *res = NULL; 33e1051a39Sopenharmony_ci EVP_MD *sha1 = EVP_MD_fetch(libctx, "SHA1", propq); 34e1051a39Sopenharmony_ci 35e1051a39Sopenharmony_ci if (sha1 == NULL) 36e1051a39Sopenharmony_ci return NULL; 37e1051a39Sopenharmony_ci 38e1051a39Sopenharmony_ci if (x != N && BN_ucmp(x, N) >= 0) 39e1051a39Sopenharmony_ci goto err; 40e1051a39Sopenharmony_ci if (y != N && BN_ucmp(y, N) >= 0) 41e1051a39Sopenharmony_ci goto err; 42e1051a39Sopenharmony_ci if ((tmp = OPENSSL_malloc(numN * 2)) == NULL) 43e1051a39Sopenharmony_ci goto err; 44e1051a39Sopenharmony_ci if (BN_bn2binpad(x, tmp, numN) < 0 45e1051a39Sopenharmony_ci || BN_bn2binpad(y, tmp + numN, numN) < 0 46e1051a39Sopenharmony_ci || !EVP_Digest(tmp, numN * 2, digest, NULL, sha1, NULL)) 47e1051a39Sopenharmony_ci goto err; 48e1051a39Sopenharmony_ci res = BN_bin2bn(digest, sizeof(digest), NULL); 49e1051a39Sopenharmony_ci err: 50e1051a39Sopenharmony_ci EVP_MD_free(sha1); 51e1051a39Sopenharmony_ci OPENSSL_free(tmp); 52e1051a39Sopenharmony_ci return res; 53e1051a39Sopenharmony_ci} 54e1051a39Sopenharmony_ci 55e1051a39Sopenharmony_cistatic BIGNUM *srp_Calc_k(const BIGNUM *N, const BIGNUM *g, 56e1051a39Sopenharmony_ci OSSL_LIB_CTX *libctx, 57e1051a39Sopenharmony_ci const char *propq) 58e1051a39Sopenharmony_ci{ 59e1051a39Sopenharmony_ci /* k = SHA1(N | PAD(g)) -- tls-srp RFC 5054 */ 60e1051a39Sopenharmony_ci return srp_Calc_xy(N, g, N, libctx, propq); 61e1051a39Sopenharmony_ci} 62e1051a39Sopenharmony_ci 63e1051a39Sopenharmony_ciBIGNUM *SRP_Calc_u_ex(const BIGNUM *A, const BIGNUM *B, const BIGNUM *N, 64e1051a39Sopenharmony_ci OSSL_LIB_CTX *libctx, const char *propq) 65e1051a39Sopenharmony_ci{ 66e1051a39Sopenharmony_ci /* u = SHA1(PAD(A) || PAD(B) ) -- tls-srp RFC 5054 */ 67e1051a39Sopenharmony_ci return srp_Calc_xy(A, B, N, libctx, propq); 68e1051a39Sopenharmony_ci} 69e1051a39Sopenharmony_ci 70e1051a39Sopenharmony_ciBIGNUM *SRP_Calc_u(const BIGNUM *A, const BIGNUM *B, const BIGNUM *N) 71e1051a39Sopenharmony_ci{ 72e1051a39Sopenharmony_ci /* u = SHA1(PAD(A) || PAD(B) ) -- tls-srp RFC 5054 */ 73e1051a39Sopenharmony_ci return srp_Calc_xy(A, B, N, NULL, NULL); 74e1051a39Sopenharmony_ci} 75e1051a39Sopenharmony_ci 76e1051a39Sopenharmony_ciBIGNUM *SRP_Calc_server_key(const BIGNUM *A, const BIGNUM *v, const BIGNUM *u, 77e1051a39Sopenharmony_ci const BIGNUM *b, const BIGNUM *N) 78e1051a39Sopenharmony_ci{ 79e1051a39Sopenharmony_ci BIGNUM *tmp = NULL, *S = NULL; 80e1051a39Sopenharmony_ci BN_CTX *bn_ctx; 81e1051a39Sopenharmony_ci 82e1051a39Sopenharmony_ci if (u == NULL || A == NULL || v == NULL || b == NULL || N == NULL) 83e1051a39Sopenharmony_ci return NULL; 84e1051a39Sopenharmony_ci 85e1051a39Sopenharmony_ci if ((bn_ctx = BN_CTX_new()) == NULL || (tmp = BN_new()) == NULL) 86e1051a39Sopenharmony_ci goto err; 87e1051a39Sopenharmony_ci 88e1051a39Sopenharmony_ci /* S = (A*v**u) ** b */ 89e1051a39Sopenharmony_ci 90e1051a39Sopenharmony_ci if (!BN_mod_exp(tmp, v, u, N, bn_ctx)) 91e1051a39Sopenharmony_ci goto err; 92e1051a39Sopenharmony_ci if (!BN_mod_mul(tmp, A, tmp, N, bn_ctx)) 93e1051a39Sopenharmony_ci goto err; 94e1051a39Sopenharmony_ci 95e1051a39Sopenharmony_ci S = BN_new(); 96e1051a39Sopenharmony_ci if (S != NULL && !BN_mod_exp(S, tmp, b, N, bn_ctx)) { 97e1051a39Sopenharmony_ci BN_free(S); 98e1051a39Sopenharmony_ci S = NULL; 99e1051a39Sopenharmony_ci } 100e1051a39Sopenharmony_ci err: 101e1051a39Sopenharmony_ci BN_CTX_free(bn_ctx); 102e1051a39Sopenharmony_ci BN_clear_free(tmp); 103e1051a39Sopenharmony_ci return S; 104e1051a39Sopenharmony_ci} 105e1051a39Sopenharmony_ci 106e1051a39Sopenharmony_ciBIGNUM *SRP_Calc_B_ex(const BIGNUM *b, const BIGNUM *N, const BIGNUM *g, 107e1051a39Sopenharmony_ci const BIGNUM *v, OSSL_LIB_CTX *libctx, const char *propq) 108e1051a39Sopenharmony_ci{ 109e1051a39Sopenharmony_ci BIGNUM *kv = NULL, *gb = NULL; 110e1051a39Sopenharmony_ci BIGNUM *B = NULL, *k = NULL; 111e1051a39Sopenharmony_ci BN_CTX *bn_ctx; 112e1051a39Sopenharmony_ci 113e1051a39Sopenharmony_ci if (b == NULL || N == NULL || g == NULL || v == NULL || 114e1051a39Sopenharmony_ci (bn_ctx = BN_CTX_new_ex(libctx)) == NULL) 115e1051a39Sopenharmony_ci return NULL; 116e1051a39Sopenharmony_ci 117e1051a39Sopenharmony_ci if ((kv = BN_new()) == NULL || 118e1051a39Sopenharmony_ci (gb = BN_new()) == NULL || (B = BN_new()) == NULL) 119e1051a39Sopenharmony_ci goto err; 120e1051a39Sopenharmony_ci 121e1051a39Sopenharmony_ci /* B = g**b + k*v */ 122e1051a39Sopenharmony_ci 123e1051a39Sopenharmony_ci if (!BN_mod_exp(gb, g, b, N, bn_ctx) 124e1051a39Sopenharmony_ci || (k = srp_Calc_k(N, g, libctx, propq)) == NULL 125e1051a39Sopenharmony_ci || !BN_mod_mul(kv, v, k, N, bn_ctx) 126e1051a39Sopenharmony_ci || !BN_mod_add(B, gb, kv, N, bn_ctx)) { 127e1051a39Sopenharmony_ci BN_free(B); 128e1051a39Sopenharmony_ci B = NULL; 129e1051a39Sopenharmony_ci } 130e1051a39Sopenharmony_ci err: 131e1051a39Sopenharmony_ci BN_CTX_free(bn_ctx); 132e1051a39Sopenharmony_ci BN_clear_free(kv); 133e1051a39Sopenharmony_ci BN_clear_free(gb); 134e1051a39Sopenharmony_ci BN_free(k); 135e1051a39Sopenharmony_ci return B; 136e1051a39Sopenharmony_ci} 137e1051a39Sopenharmony_ci 138e1051a39Sopenharmony_ciBIGNUM *SRP_Calc_B(const BIGNUM *b, const BIGNUM *N, const BIGNUM *g, 139e1051a39Sopenharmony_ci const BIGNUM *v) 140e1051a39Sopenharmony_ci{ 141e1051a39Sopenharmony_ci return SRP_Calc_B_ex(b, N, g, v, NULL, NULL); 142e1051a39Sopenharmony_ci} 143e1051a39Sopenharmony_ci 144e1051a39Sopenharmony_ciBIGNUM *SRP_Calc_x_ex(const BIGNUM *s, const char *user, const char *pass, 145e1051a39Sopenharmony_ci OSSL_LIB_CTX *libctx, const char *propq) 146e1051a39Sopenharmony_ci{ 147e1051a39Sopenharmony_ci unsigned char dig[SHA_DIGEST_LENGTH]; 148e1051a39Sopenharmony_ci EVP_MD_CTX *ctxt; 149e1051a39Sopenharmony_ci unsigned char *cs = NULL; 150e1051a39Sopenharmony_ci BIGNUM *res = NULL; 151e1051a39Sopenharmony_ci EVP_MD *sha1 = NULL; 152e1051a39Sopenharmony_ci 153e1051a39Sopenharmony_ci if ((s == NULL) || (user == NULL) || (pass == NULL)) 154e1051a39Sopenharmony_ci return NULL; 155e1051a39Sopenharmony_ci 156e1051a39Sopenharmony_ci ctxt = EVP_MD_CTX_new(); 157e1051a39Sopenharmony_ci if (ctxt == NULL) 158e1051a39Sopenharmony_ci return NULL; 159e1051a39Sopenharmony_ci if ((cs = OPENSSL_malloc(BN_num_bytes(s))) == NULL) 160e1051a39Sopenharmony_ci goto err; 161e1051a39Sopenharmony_ci 162e1051a39Sopenharmony_ci sha1 = EVP_MD_fetch(libctx, "SHA1", propq); 163e1051a39Sopenharmony_ci if (sha1 == NULL) 164e1051a39Sopenharmony_ci goto err; 165e1051a39Sopenharmony_ci 166e1051a39Sopenharmony_ci if (!EVP_DigestInit_ex(ctxt, sha1, NULL) 167e1051a39Sopenharmony_ci || !EVP_DigestUpdate(ctxt, user, strlen(user)) 168e1051a39Sopenharmony_ci || !EVP_DigestUpdate(ctxt, ":", 1) 169e1051a39Sopenharmony_ci || !EVP_DigestUpdate(ctxt, pass, strlen(pass)) 170e1051a39Sopenharmony_ci || !EVP_DigestFinal_ex(ctxt, dig, NULL) 171e1051a39Sopenharmony_ci || !EVP_DigestInit_ex(ctxt, sha1, NULL)) 172e1051a39Sopenharmony_ci goto err; 173e1051a39Sopenharmony_ci if (BN_bn2bin(s, cs) < 0) 174e1051a39Sopenharmony_ci goto err; 175e1051a39Sopenharmony_ci if (!EVP_DigestUpdate(ctxt, cs, BN_num_bytes(s))) 176e1051a39Sopenharmony_ci goto err; 177e1051a39Sopenharmony_ci 178e1051a39Sopenharmony_ci if (!EVP_DigestUpdate(ctxt, dig, sizeof(dig)) 179e1051a39Sopenharmony_ci || !EVP_DigestFinal_ex(ctxt, dig, NULL)) 180e1051a39Sopenharmony_ci goto err; 181e1051a39Sopenharmony_ci 182e1051a39Sopenharmony_ci res = BN_bin2bn(dig, sizeof(dig), NULL); 183e1051a39Sopenharmony_ci 184e1051a39Sopenharmony_ci err: 185e1051a39Sopenharmony_ci EVP_MD_free(sha1); 186e1051a39Sopenharmony_ci OPENSSL_free(cs); 187e1051a39Sopenharmony_ci EVP_MD_CTX_free(ctxt); 188e1051a39Sopenharmony_ci return res; 189e1051a39Sopenharmony_ci} 190e1051a39Sopenharmony_ci 191e1051a39Sopenharmony_ciBIGNUM *SRP_Calc_x(const BIGNUM *s, const char *user, const char *pass) 192e1051a39Sopenharmony_ci{ 193e1051a39Sopenharmony_ci return SRP_Calc_x_ex(s, user, pass, NULL, NULL); 194e1051a39Sopenharmony_ci} 195e1051a39Sopenharmony_ci 196e1051a39Sopenharmony_ciBIGNUM *SRP_Calc_A(const BIGNUM *a, const BIGNUM *N, const BIGNUM *g) 197e1051a39Sopenharmony_ci{ 198e1051a39Sopenharmony_ci BN_CTX *bn_ctx; 199e1051a39Sopenharmony_ci BIGNUM *A = NULL; 200e1051a39Sopenharmony_ci 201e1051a39Sopenharmony_ci if (a == NULL || N == NULL || g == NULL || (bn_ctx = BN_CTX_new()) == NULL) 202e1051a39Sopenharmony_ci return NULL; 203e1051a39Sopenharmony_ci 204e1051a39Sopenharmony_ci if ((A = BN_new()) != NULL && !BN_mod_exp(A, g, a, N, bn_ctx)) { 205e1051a39Sopenharmony_ci BN_free(A); 206e1051a39Sopenharmony_ci A = NULL; 207e1051a39Sopenharmony_ci } 208e1051a39Sopenharmony_ci BN_CTX_free(bn_ctx); 209e1051a39Sopenharmony_ci return A; 210e1051a39Sopenharmony_ci} 211e1051a39Sopenharmony_ci 212e1051a39Sopenharmony_ciBIGNUM *SRP_Calc_client_key_ex(const BIGNUM *N, const BIGNUM *B, const BIGNUM *g, 213e1051a39Sopenharmony_ci const BIGNUM *x, const BIGNUM *a, const BIGNUM *u, 214e1051a39Sopenharmony_ci OSSL_LIB_CTX *libctx, const char *propq) 215e1051a39Sopenharmony_ci{ 216e1051a39Sopenharmony_ci BIGNUM *tmp = NULL, *tmp2 = NULL, *tmp3 = NULL, *k = NULL, *K = NULL; 217e1051a39Sopenharmony_ci BIGNUM *xtmp = NULL; 218e1051a39Sopenharmony_ci BN_CTX *bn_ctx; 219e1051a39Sopenharmony_ci 220e1051a39Sopenharmony_ci if (u == NULL || B == NULL || N == NULL || g == NULL || x == NULL 221e1051a39Sopenharmony_ci || a == NULL || (bn_ctx = BN_CTX_new_ex(libctx)) == NULL) 222e1051a39Sopenharmony_ci return NULL; 223e1051a39Sopenharmony_ci 224e1051a39Sopenharmony_ci if ((tmp = BN_new()) == NULL || 225e1051a39Sopenharmony_ci (tmp2 = BN_new()) == NULL || 226e1051a39Sopenharmony_ci (tmp3 = BN_new()) == NULL || 227e1051a39Sopenharmony_ci (xtmp = BN_new()) == NULL) 228e1051a39Sopenharmony_ci goto err; 229e1051a39Sopenharmony_ci 230e1051a39Sopenharmony_ci BN_with_flags(xtmp, x, BN_FLG_CONSTTIME); 231e1051a39Sopenharmony_ci BN_set_flags(tmp, BN_FLG_CONSTTIME); 232e1051a39Sopenharmony_ci if (!BN_mod_exp(tmp, g, xtmp, N, bn_ctx)) 233e1051a39Sopenharmony_ci goto err; 234e1051a39Sopenharmony_ci if ((k = srp_Calc_k(N, g, libctx, propq)) == NULL) 235e1051a39Sopenharmony_ci goto err; 236e1051a39Sopenharmony_ci if (!BN_mod_mul(tmp2, tmp, k, N, bn_ctx)) 237e1051a39Sopenharmony_ci goto err; 238e1051a39Sopenharmony_ci if (!BN_mod_sub(tmp, B, tmp2, N, bn_ctx)) 239e1051a39Sopenharmony_ci goto err; 240e1051a39Sopenharmony_ci if (!BN_mul(tmp3, u, xtmp, bn_ctx)) 241e1051a39Sopenharmony_ci goto err; 242e1051a39Sopenharmony_ci if (!BN_add(tmp2, a, tmp3)) 243e1051a39Sopenharmony_ci goto err; 244e1051a39Sopenharmony_ci K = BN_new(); 245e1051a39Sopenharmony_ci if (K != NULL && !BN_mod_exp(K, tmp, tmp2, N, bn_ctx)) { 246e1051a39Sopenharmony_ci BN_free(K); 247e1051a39Sopenharmony_ci K = NULL; 248e1051a39Sopenharmony_ci } 249e1051a39Sopenharmony_ci 250e1051a39Sopenharmony_ci err: 251e1051a39Sopenharmony_ci BN_CTX_free(bn_ctx); 252e1051a39Sopenharmony_ci BN_free(xtmp); 253e1051a39Sopenharmony_ci BN_clear_free(tmp); 254e1051a39Sopenharmony_ci BN_clear_free(tmp2); 255e1051a39Sopenharmony_ci BN_clear_free(tmp3); 256e1051a39Sopenharmony_ci BN_free(k); 257e1051a39Sopenharmony_ci return K; 258e1051a39Sopenharmony_ci} 259e1051a39Sopenharmony_ci 260e1051a39Sopenharmony_ciBIGNUM *SRP_Calc_client_key(const BIGNUM *N, const BIGNUM *B, const BIGNUM *g, 261e1051a39Sopenharmony_ci const BIGNUM *x, const BIGNUM *a, const BIGNUM *u) 262e1051a39Sopenharmony_ci{ 263e1051a39Sopenharmony_ci return SRP_Calc_client_key_ex(N, B, g, x, a, u, NULL, NULL); 264e1051a39Sopenharmony_ci} 265e1051a39Sopenharmony_ci 266e1051a39Sopenharmony_ciint SRP_Verify_B_mod_N(const BIGNUM *B, const BIGNUM *N) 267e1051a39Sopenharmony_ci{ 268e1051a39Sopenharmony_ci BIGNUM *r; 269e1051a39Sopenharmony_ci BN_CTX *bn_ctx; 270e1051a39Sopenharmony_ci int ret = 0; 271e1051a39Sopenharmony_ci 272e1051a39Sopenharmony_ci if (B == NULL || N == NULL || (bn_ctx = BN_CTX_new()) == NULL) 273e1051a39Sopenharmony_ci return 0; 274e1051a39Sopenharmony_ci 275e1051a39Sopenharmony_ci if ((r = BN_new()) == NULL) 276e1051a39Sopenharmony_ci goto err; 277e1051a39Sopenharmony_ci /* Checks if B % N == 0 */ 278e1051a39Sopenharmony_ci if (!BN_nnmod(r, B, N, bn_ctx)) 279e1051a39Sopenharmony_ci goto err; 280e1051a39Sopenharmony_ci ret = !BN_is_zero(r); 281e1051a39Sopenharmony_ci err: 282e1051a39Sopenharmony_ci BN_CTX_free(bn_ctx); 283e1051a39Sopenharmony_ci BN_free(r); 284e1051a39Sopenharmony_ci return ret; 285e1051a39Sopenharmony_ci} 286e1051a39Sopenharmony_ci 287e1051a39Sopenharmony_ciint SRP_Verify_A_mod_N(const BIGNUM *A, const BIGNUM *N) 288e1051a39Sopenharmony_ci{ 289e1051a39Sopenharmony_ci /* Checks if A % N == 0 */ 290e1051a39Sopenharmony_ci return SRP_Verify_B_mod_N(A, N); 291e1051a39Sopenharmony_ci} 292e1051a39Sopenharmony_ci 293e1051a39Sopenharmony_cistatic SRP_gN knowngN[] = { 294e1051a39Sopenharmony_ci {"8192", &ossl_bn_generator_19, &ossl_bn_group_8192}, 295e1051a39Sopenharmony_ci {"6144", &ossl_bn_generator_5, &ossl_bn_group_6144}, 296e1051a39Sopenharmony_ci {"4096", &ossl_bn_generator_5, &ossl_bn_group_4096}, 297e1051a39Sopenharmony_ci {"3072", &ossl_bn_generator_5, &ossl_bn_group_3072}, 298e1051a39Sopenharmony_ci {"2048", &ossl_bn_generator_2, &ossl_bn_group_2048}, 299e1051a39Sopenharmony_ci {"1536", &ossl_bn_generator_2, &ossl_bn_group_1536}, 300e1051a39Sopenharmony_ci {"1024", &ossl_bn_generator_2, &ossl_bn_group_1024}, 301e1051a39Sopenharmony_ci}; 302e1051a39Sopenharmony_ci 303e1051a39Sopenharmony_ci# define KNOWN_GN_NUMBER sizeof(knowngN) / sizeof(SRP_gN) 304e1051a39Sopenharmony_ci 305e1051a39Sopenharmony_ci/* 306e1051a39Sopenharmony_ci * Check if G and N are known parameters. The values have been generated 307e1051a39Sopenharmony_ci * from the IETF RFC 5054 308e1051a39Sopenharmony_ci */ 309e1051a39Sopenharmony_cichar *SRP_check_known_gN_param(const BIGNUM *g, const BIGNUM *N) 310e1051a39Sopenharmony_ci{ 311e1051a39Sopenharmony_ci size_t i; 312e1051a39Sopenharmony_ci if ((g == NULL) || (N == NULL)) 313e1051a39Sopenharmony_ci return NULL; 314e1051a39Sopenharmony_ci 315e1051a39Sopenharmony_ci for (i = 0; i < KNOWN_GN_NUMBER; i++) { 316e1051a39Sopenharmony_ci if (BN_cmp(knowngN[i].g, g) == 0 && BN_cmp(knowngN[i].N, N) == 0) 317e1051a39Sopenharmony_ci return knowngN[i].id; 318e1051a39Sopenharmony_ci } 319e1051a39Sopenharmony_ci return NULL; 320e1051a39Sopenharmony_ci} 321e1051a39Sopenharmony_ci 322e1051a39Sopenharmony_ciSRP_gN *SRP_get_default_gN(const char *id) 323e1051a39Sopenharmony_ci{ 324e1051a39Sopenharmony_ci size_t i; 325e1051a39Sopenharmony_ci 326e1051a39Sopenharmony_ci if (id == NULL) 327e1051a39Sopenharmony_ci return knowngN; 328e1051a39Sopenharmony_ci for (i = 0; i < KNOWN_GN_NUMBER; i++) { 329e1051a39Sopenharmony_ci if (strcmp(knowngN[i].id, id) == 0) 330e1051a39Sopenharmony_ci return knowngN + i; 331e1051a39Sopenharmony_ci } 332e1051a39Sopenharmony_ci return NULL; 333e1051a39Sopenharmony_ci} 334e1051a39Sopenharmony_ci#endif 335