Мне нужно проверить идентификатор google id_token, и один шаг включает проверку сигнатуры токена.Ошибка проверки маркера Golang
Сначала я получаю сертификат от: https://www.googleapis.com/oauth2/v2/certs и извлекаю часть модуля (n) и экспоненты (e) из сертификата и генерирую открытый ключ, затем я разделяю токен (заголовок, полезную нагрузку и дайджест), после чего Я отправляю декодированный header.payload
вместе с дайджестом pKey + Google в функцию rsa rsa.VerifyPKCS1v15
.
Я застрял с этой ошибкой проверки: crypto/rsa: verification error
Вот код (я комментировал часть кода, который терпит неудачу с // validation here fails
):
func ValidateIDToken(auth_token string) (err error){
res, err := http.Get("https://www.googleapis.com/oauth2/v2/certs")
if err != nil {
log.Fatal(err)
return err
}
certs, err := ioutil.ReadAll(res.Body)
res.Body.Close()
if err != nil {
log.Fatal(err)
return err
}
//get modulus and exponent from the cert
var goCertificate interface{}
err = json.Unmarshal(certs, &goCertificate)
k := goCertificate.(map[string]interface{})["keys"]
j := k.([]interface{})
x := j[1]
h := x.(map[string]interface{})["n"]
g := x.(map[string]interface{})["e"]
e64 := base64.StdEncoding
//build the google pub key
nStr := h.(string)
decN, err := base64.StdEncoding.DecodeString(nStr)
if err != nil {
log.Println(err)
return
}
n := big.NewInt(0)
n.SetBytes(decN)
eStr := g.(string)
decE, err := base64.StdEncoding.DecodeString(eStr)
if err != nil {
log.Println(err)
return
}
var eBytes []byte
if len(decE) < 8 {
eBytes = make([]byte, 8-len(decE), 8)
eBytes = append(eBytes, decE...)
} else {
eBytes = decE
}
eReader := bytes.NewReader(eBytes)
var e uint64
err = binary.Read(eReader, binary.BigEndian, &e)
if err != nil {
log.Println(err)
return
}
pKey := rsa.PublicKey{N: n, E: int(e)}
w := strings.SplitAfter(auth_token, ".")
for i, val := range w {
w[i] = strings.Trim(val, ".")
}
y := w[0:2]
//Join just the first two parts, the header and the payload without the signature
o := strings.Join(y, ".")
headerOauth := DecodeB64(nil,[]byte(w[0]),e64)
inblockOauth := DecodeB64(nil,[]byte(w[1]),e64)
toHash := string(headerOauth) + "}." + string(inblockOauth)
digestOauth := DecodeB64(nil, []byte(w[2]),e64)
hasherOauth := sha256.New()
hasherOauth.Write([]byte(toHash))
// validation here fails
err = rsa.VerifyPKCS1v15(&pKey,crypto.SHA256,hasherOauth.Sum(nil),digestOauth)
if err != nil {
log.Printf("Error verifying key %s",err.Error())
return err
}
return err
}
UPDATE 1: Вот toHash вар, который содержит заголовок и полезную нагрузку:
{"alg":"RS256","kid":"d91c503452d0f8849200a321ffbf7dea76f9371d"}.{"iss":"accounts.google.com","sub":"104869993929250743503","azp":"[email protected]","email":"[email protected]","at_hash":"KAm1M0g-ssMkdjds7jkbVQ","email_verified":true,"aud":[email protected]","hd":"test.hr","iat":1412246551,"exp":1412250451}
UPDATE 2: Спасибо за ответ @Florent Morselli, я попробовал еще раз, и он потерпел неудачу, я на этот раз B64decoded только третья часть (подпись), но ошибка все еще была там, может кто-то проверить ее с помощью своего auth_token, просто поместите идентификатор ID в переменную auth_token ниже в коде, и дайте мне знать, если это сработает, спасибо.
package main
import(
"strings"
"encoding/binary"
"errors"
"fmt"
"log"
"encoding/base64"
"io/ioutil"
"crypto"
"crypto/sha256"
"crypto/rsa"
"bytes"
"encoding/json"
"net/http"
"math/big"
)
func main() {
auth_token := ""
w := strings.SplitAfter(auth_token, ".")
for i, val := range w {
w[i] = strings.Trim(val, ".")
}
headerOauth, err := base64.URLEncoding.DecodeString(w[0])
res, err := http.Get("https://www.googleapis.com/oauth2/v2/certs")
if err != nil {
fmt.Println(err)
}
certs, err := ioutil.ReadAll(res.Body)
res.Body.Close()
if err != nil {
fmt.Println(err)
}
//extract kid from token header
var header interface{}
err = json.Unmarshal([]byte(string(headerOauth)+"}"), &header)
token_kid := header.(map[string]interface{})["kid"]
fmt.Println("By 1")
//get modulus and exponent from the cert
var goCertificate interface{}
err = json.Unmarshal(certs, &goCertificate)
//k := goCertificate.(map[string]interface{})[token_kid.(string)]
k := goCertificate.(map[string]interface{})["keys"]
///*mod & exp part
j := k.([]interface{})
x := j[0]
if j[0].(map[string]interface{})["kid"] == token_kid {
x = j[0]
}else{
if j[1].(map[string]interface{})["kid"] == token_kid {
x = j[1]
}else{
errors.New("Token is not valid, kid from token and certificate don't match")
}
}
h := x.(map[string]interface{})["n"]
g := x.(map[string]interface{})["e"]
//build the google pub key
nStr := h.(string)
decN, err := base64.URLEncoding.DecodeString(nStr)
if err != nil {
fmt.Println(err)
return
}
n := big.NewInt(0)
n.SetBytes(decN)
eStr := g.(string)
decE, err := base64.URLEncoding.DecodeString(eStr)
if err != nil {
fmt.Println(err)
return
}
var eBytes []byte
if len(decE) < 8 {
eBytes = make([]byte, 8-len(decE), 8)
eBytes = append(eBytes, decE...)
} else {
eBytes = decE
}
eReader := bytes.NewReader(eBytes)
var e uint64
err = binary.Read(eReader, binary.BigEndian, &e)
if err != nil {
log.Println(err)
return
}
pKey := rsa.PublicKey{N: n, E: int(e)}
//inblockOauth := base64.URLEncoding.DecodeString(w[1])
toHash := w[0] + "." + w[1]
digestOauth, err := base64.URLEncoding.DecodeString(w[2])
hasherOauth := sha256.New()
hasherOauth.Write([]byte(toHash))
// verification here fails
err = rsa.VerifyPKCS1v15(&pKey,crypto.SHA256,hasherOauth.Sum(nil),digestOauth)
if err != nil {
fmt.Printf("Error verifying key %s",err.Error())
}
}
@RickyA - криптографический/RSA: ошибка верификации – CroiOS
у вас есть тест auth_token проверить с? – RickyA
@RickyA - У меня есть обновленный вопрос (я поставил содержимое переменной toHash в конце вопроса) – CroiOS