@@ -207,6 +207,15 @@ std::string b64url_decode_nopadding(const std::string &input)
207207}
208208
209209
210+ // Base64-encode without padding.
211+ std::string b64url_encode_nopadding (const std::string &input)
212+ {
213+ std::string result = jwt::base::encode<local_base64url>(input);
214+ auto pos = result.find (" =" );
215+ return result.substr (0 , pos);
216+ }
217+
218+
210219std::string
211220es256_from_coords (const std::string &x_str, const std::string &y_str) {
212221 auto x_decode = b64url_decode_nopadding (x_str);
@@ -484,6 +493,63 @@ Validator::get_public_key_pem(const std::string &issuer, const std::string &kid,
484493}
485494
486495
496+ bool
497+ scitokens::Validator::store_public_ec_key (const std::string &issuer, const std::string &keyid,
498+ const std::string &public_key)
499+ {
500+ std::unique_ptr<BIO, decltype (&BIO_free_all)> pubkey_bio (BIO_new (BIO_s_mem ()), BIO_free_all);
501+ if ((size_t )BIO_write (pubkey_bio.get (), public_key.data (), public_key.size ()) != public_key.size ()) {
502+ return false ;
503+ }
504+ std::unique_ptr<EC_KEY, decltype (&EC_KEY_free)> pkey
505+ (PEM_read_bio_EC_PUBKEY (pubkey_bio.get (), nullptr , nullptr , nullptr ), EC_KEY_free);
506+ if (!pkey) {return false ;}
507+
508+ EC_GROUP *params = (EC_GROUP *)EC_KEY_get0_group (pkey.get ());
509+ if (!params) {
510+ throw UnsupportedKeyException (" Unable to get OpenSSL EC group" );
511+ }
512+
513+ const EC_POINT *point = EC_KEY_get0_public_key (pkey.get ());
514+ if (!point) {
515+ throw UnsupportedKeyException (" Unable to get OpenSSL EC point" );
516+ }
517+
518+ std::unique_ptr<BIGNUM, decltype (&BN_free)> x_bignum (BN_new (), BN_free);
519+ std::unique_ptr<BIGNUM, decltype (&BN_free)> y_bignum (BN_new (), BN_free);
520+ if (!EC_POINT_get_affine_coordinates_GFp (params, point, x_bignum.get (), y_bignum.get (), nullptr )) {
521+ throw UnsupportedKeyException (" Unable to get OpenSSL affine coordinates" );
522+ }
523+
524+ auto x_num = BN_num_bytes (x_bignum.get ());
525+ auto y_num = BN_num_bytes (y_bignum.get ());
526+ std::vector<unsigned char > x_bin; x_bin.reserve (x_num);
527+ std::vector<unsigned char > y_bin; y_bin.reserve (y_num);
528+ BN_bn2bin (x_bignum.get (), &x_bin[0 ]);
529+ BN_bn2bin (y_bignum.get (), &y_bin[0 ]);
530+ std::string x_str (reinterpret_cast <char *>(&x_bin[0 ]), x_num);
531+ std::string y_str (reinterpret_cast <char *>(&y_bin[0 ]), y_num);
532+
533+ picojson::object key_obj;
534+ key_obj[" alg" ] = picojson::value (" ES256" );
535+ key_obj[" kid" ] = picojson::value (keyid);
536+ key_obj[" use" ] = picojson::value (" sig" );
537+ key_obj[" kty" ] = picojson::value (" EC" );
538+ key_obj[" x" ] = picojson::value (b64url_encode_nopadding (x_str));
539+ key_obj[" y" ] = picojson::value (b64url_encode_nopadding (y_str));
540+ std::vector<picojson::value> key_list;
541+ key_list.emplace_back (key_obj);
542+
543+ picojson::object top_obj;
544+ top_obj[" keys" ] = picojson::value (key_list);
545+
546+ picojson::value top_value (top_obj);
547+
548+ auto now = std::time (NULL );
549+ return store_public_keys (issuer, top_value, now + 600 , now + 4 *3600 );
550+ }
551+
552+
487553bool
488554scitokens::Enforcer::scope_validator (const jwt::claim &claim, void *myself) {
489555 auto me = reinterpret_cast <scitokens::Enforcer*>(myself);
0 commit comments