1
1
use std:: io:: Read ;
2
2
3
- use crypto:: hmac:: Hmac ;
4
- use crypto:: mac:: Mac ;
5
- use crypto:: mac:: MacResult ;
6
- use crypto:: sha1:: Sha1 ;
7
3
use hex:: FromHex ;
4
+ use openssl:: { hash:: MessageDigest , memcmp, pkey:: PKey , sign:: Signer } ;
8
5
use rocket:: data:: { self , Data , FromDataSimple } ;
9
6
use rocket:: http:: Status ;
10
7
use rocket:: outcome:: Outcome :: * ;
@@ -27,7 +24,7 @@ impl FromDataSimple for Event {
27
24
let headers = request. headers ( ) ;
28
25
29
26
// 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 " ) {
31
28
Some ( s) => s,
32
29
None => return Failure ( ( Status :: BadRequest , "missing signature header" ) ) ,
33
30
} ;
@@ -51,7 +48,7 @@ impl FromDataSimple for Event {
51
48
}
52
49
53
50
for secret in & CONFIG . github_webhook_secrets {
54
- if authenticate ( secret, & body, signature) {
51
+ if authenticate ( secret, & body, signature) . is_ok ( ) {
55
52
// once we know it's from github, we'll parse it
56
53
57
54
let payload = match parse_event ( event_name, & body) {
@@ -97,16 +94,19 @@ impl FromDataSimple for Event {
97
94
}
98
95
}
99
96
100
- fn authenticate ( secret : & str , payload : & str , signature : & str ) -> bool {
97
+ fn authenticate ( secret : & str , payload : & str , signature : & str ) -> Result < ( ) , ( ) > {
101
98
// 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 ( ( ) )
108
108
} else {
109
- false
109
+ Err ( ( ) )
110
110
}
111
111
}
112
112
0 commit comments