11use std:: io:: Read ;
22
3- use crypto:: hmac:: Hmac ;
4- use crypto:: mac:: Mac ;
5- use crypto:: mac:: MacResult ;
6- use crypto:: sha1:: Sha1 ;
73use hex:: FromHex ;
4+ use openssl:: { hash:: MessageDigest , memcmp, pkey:: PKey , sign:: Signer } ;
85use rocket:: data:: { self , Data , FromDataSimple } ;
96use rocket:: http:: Status ;
107use rocket:: outcome:: Outcome :: * ;
@@ -27,7 +24,7 @@ impl FromDataSimple for Event {
2724 let headers = request. headers ( ) ;
2825
2926 // see [this document](https://developer.github.com/webhooks/securing/) for more information
30- let signature = match headers. get_one ( "X-Hub-Signature" ) {
27+ let signature = match headers. get_one ( "X-Hub-Signature-256 " ) {
3128 Some ( s) => s,
3229 None => return Failure ( ( Status :: BadRequest , "missing signature header" ) ) ,
3330 } ;
@@ -51,7 +48,7 @@ impl FromDataSimple for Event {
5148 }
5249
5350 for secret in & CONFIG . github_webhook_secrets {
54- if authenticate ( secret, & body, signature) {
51+ if authenticate ( secret, & body, signature) . is_ok ( ) {
5552 // once we know it's from github, we'll parse it
5653
5754 let payload = match parse_event ( event_name, & body) {
@@ -97,16 +94,19 @@ impl FromDataSimple for Event {
9794 }
9895}
9996
100- fn authenticate ( secret : & str , payload : & str , signature : & str ) -> bool {
97+ fn authenticate ( secret : & str , payload : & str , signature : & str ) -> Result < ( ) , ( ) > {
10198 // https://developer.github.com/webhooks/securing/#validating-payloads-from-github
102- let sans_prefix = signature[ 5 ..] . as_bytes ( ) ;
103- if let Ok ( sigbytes) = Vec :: from_hex ( sans_prefix) {
104- let mut mac = Hmac :: new ( Sha1 :: new ( ) , secret. as_bytes ( ) ) ;
105- mac. input ( payload. as_bytes ( ) ) ;
106- // constant time comparison
107- mac. result ( ) == MacResult :: new ( & sigbytes)
99+ let signature = signature. get ( "sha256=" . len ( ) ..) . ok_or ( ( ) ) ?. as_bytes ( ) ;
100+ let signature = Vec :: from_hex ( signature) . map_err ( |_| ( ) ) ?;
101+ let key = PKey :: hmac ( secret. as_bytes ( ) ) . map_err ( |_| ( ) ) ?;
102+ let mut signer = Signer :: new ( MessageDigest :: sha256 ( ) , & key) . map_err ( |_| ( ) ) ?;
103+ signer. update ( payload. as_bytes ( ) ) . map_err ( |_| ( ) ) ?;
104+ let hmac = signer. sign_to_vec ( ) . map_err ( |_| ( ) ) ?;
105+ // constant time comparison
106+ if memcmp:: eq ( & hmac, & signature) {
107+ Ok ( ( ) )
108108 } else {
109- false
109+ Err ( ( ) )
110110 }
111111}
112112
0 commit comments