1+ #include " p256verify.h"
2+ #include " plugin_util.h"
3+
4+ extern " C" {
5+
6+ // Helper: Create public key EVP_PKEY object
7+ static EVP_PKEY *p256_pubkey_from_coords (const unsigned char *qx, const unsigned char *qy);
8+ // Helper: Build signature from raw (r, s) components
9+ static unsigned char *p256_sig_to_der (const unsigned char *r_bytes, const unsigned char *s_bytes, int *out_len);
10+ // Helper: Perform ECDSA verification with pre-hashed data
11+ static int p256_verify_prehash (EVP_PKEY *pkey, const unsigned char *sig_der, int sig_len, const unsigned char *hash, size_t hash_len);
12+
13+ struct string *hook_KRYPTO_p256verify (struct string *input) {
14+ // The precompile expects exactly 160 bytes: h || r || s || qx || qy
15+ if (len (input) != 160 ) {
16+ return allocString (0 );
17+ }
18+
19+ // 32-bytes slices
20+ const unsigned char *data = (unsigned char *)input->data ;
21+ const unsigned char *h = data;
22+ const unsigned char *r_bytes = data + 32 ;
23+ const unsigned char *s_bytes = data + 64 ;
24+ const unsigned char *qx = data + 96 ;
25+ const unsigned char *qy = data + 128 ;
26+
27+ EVP_PKEY *pkey = p256_pubkey_from_coords (qx, qy);
28+ if (!pkey) {
29+ return allocString (0 );
30+ }
31+
32+ int sig_der_len = 0 ;
33+ unsigned char *sig_der = p256_sig_to_der (r_bytes, s_bytes, &sig_der_len);
34+ if (!sig_der) {
35+ EVP_PKEY_free (pkey);
36+ return allocString (0 );
37+ }
38+
39+ int valid = p256_verify_prehash (pkey, sig_der, sig_der_len, h, 32 );
40+
41+ OPENSSL_free (sig_der);
42+ EVP_PKEY_free (pkey);
43+
44+ if (valid) {
45+ unsigned char result[32 ] = {0 };
46+ result[31 ] = 1 ;
47+ return raw (result, 32 );
48+ }
49+ return allocString (0 );
50+ }
51+
52+ static EVP_PKEY *p256_pubkey_from_coords (const unsigned char *qx, const unsigned char *qy) {
53+ // Build SEC1 uncompressed format: 0x04 || x || y
54+ unsigned char pubkey_uncompressed[65 ];
55+ pubkey_uncompressed[0 ] = 0x04 ;
56+ memcpy (pubkey_uncompressed + 1 , qx, 32 );
57+ memcpy (pubkey_uncompressed + 33 , qy, 32 );
58+
59+ EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_from_name (NULL , " EC" , NULL );
60+ if (!pctx) {
61+ return NULL ;
62+ }
63+
64+ if (EVP_PKEY_fromdata_init (pctx) <= 0 ) {
65+ EVP_PKEY_CTX_free (pctx);
66+ return NULL ;
67+ }
68+
69+ OSSL_PARAM params[] = {
70+ OSSL_PARAM_construct_utf8_string (OSSL_PKEY_PARAM_GROUP_NAME, (char *)" prime256v1" , 0 ),
71+ OSSL_PARAM_construct_octet_string (OSSL_PKEY_PARAM_PUB_KEY, pubkey_uncompressed, 65 ),
72+ OSSL_PARAM_construct_end ()
73+ };
74+
75+ EVP_PKEY *pkey = NULL ;
76+ if (EVP_PKEY_fromdata (pctx, &pkey, EVP_PKEY_PUBLIC_KEY, params) <= 0 ) {
77+ EVP_PKEY_CTX_free (pctx);
78+ return NULL ;
79+ }
80+
81+ EVP_PKEY_CTX_free (pctx);
82+ return pkey;
83+ }
84+
85+ static unsigned char *p256_sig_to_der (const unsigned char *r_bytes, const unsigned char *s_bytes, int *out_len) {
86+ ECDSA_SIG *sig = ECDSA_SIG_new ();
87+ if (!sig) {
88+ return NULL ;
89+ }
90+
91+ BIGNUM *bn_r = BN_bin2bn (r_bytes, 32 , NULL );
92+ BIGNUM *bn_s = BN_bin2bn (s_bytes, 32 , NULL );
93+
94+ if (!bn_r || !bn_s || !ECDSA_SIG_set0 (sig, bn_r, bn_s)) {
95+ // Note: ECDSA_SIG_set0 takes ownership on success, so only free on failure
96+ if (bn_r) BN_free (bn_r);
97+ if (bn_s) BN_free (bn_s);
98+ ECDSA_SIG_free (sig);
99+ return NULL ;
100+ }
101+
102+ unsigned char *sig_der = NULL ;
103+ *out_len = i2d_ECDSA_SIG (sig, &sig_der);
104+ ECDSA_SIG_free (sig);
105+
106+ if (*out_len <= 0 ) {
107+ return NULL ;
108+ }
109+
110+ return sig_der;
111+ }
112+
113+ static int p256_verify_prehash (EVP_PKEY *pkey, const unsigned char *sig_der, int sig_len, const unsigned char *hash, size_t hash_len) {
114+ EVP_PKEY_CTX *vctx = EVP_PKEY_CTX_new (pkey, NULL );
115+ if (!vctx) {
116+ return 0 ;
117+ }
118+
119+ int result = 0 ;
120+ if (EVP_PKEY_verify_init (vctx) > 0 ) {
121+ result = (EVP_PKEY_verify (vctx, sig_der, sig_len, hash, hash_len) == 1 );
122+ }
123+
124+ EVP_PKEY_CTX_free (vctx);
125+ return result;
126+ }
127+
128+ }
0 commit comments