ipsBruno / haval-h6-gwm-alexa-chatgpt-mqtt-integration

A f** challenge
13 stars 3 forks source link

certificateHandle in NodeJS #2

Open ipsBruno opened 5 months ago

ipsBruno commented 5 months ago

Hoje o projeto utiliza um .exe em C# para fazer o handler do certificado com os servidores da GWM e realizar as requisições

O código foi baseado nesse projeto do pessoal da ora2mqtt

https://github.com/zivillian/ora2mqtt/blob/main/libgwmapi/CertificateHandler.cs

Tentei fazer o mesmo código sem sucesso em NodeJS por limitações de funções de manipulação RSA, sei que existe bibliotecas que possam ajudar como node-forge e asn1.js mas a GWM fez bastante complicado justamente pra dificultar qualquer ssl pinning por parte de desenvolvedores e hackers


Currently, the project uses a .exe in C# to handle the certificate with GWM servers and make requests.

The code was based on this project from the ora2mqtt team:

https://github.com/zivillian/ora2mqtt/blob/main/libgwmapi/CertificateHandler.cs

I tried to replicate the same code in NodeJS without success due to limitations in RSA manipulation functions. I know there are libraries that can help, such as node-forge and asn1.js, but GWM made it quite complicated specifically to hinder any SSL pinning attempts by developers and hackers.

ricardopadilha commented 3 months ago

Eu consegui extrair a chave privada em formato PEM. Basicamente precisa pegar o RSAParameters e serializar ele corretamente. A chave privada que está no repositório não funciona porque o exponente que está no arquivo da chave privada está errado. O CertificateHandler corrige isso em aqui.

Aqui vai o arquivo da chave privada, baseado nos certificados que você tem no repositório hoje:

-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAtWMft4X2LfwaFwSy3dmAykPBxkRdRPW5NwFDz9WOsi9tpnCe
ivF19Lgyfx2CQtfjyxSMdfjOAHQNQu8+Q3NcDTt8tLkhgDbjyoSJdH45do2/l01j
UNd+Zj1RWJaXZ+rBfIAqqjlFnvzuBDHbkqNIQs1eJnNBYwmnPPKyUvZhNlbrzqwg
1VAUzIjz/WyLpCdM90Zlomi+CTsZecRb19h8I1auczCQbz2A5zT1Q8Ju5ctFIYZU
W5xzZ9elJXB33r/9U2ojNxLzZnIANJJ5LWSEzbWIqk6gkvrBfMMausQxusQrhNF0
YOdgctO27WgAh8oLO6DLPpCwKNO4qdj/avansQIDAQABAoIBAQCYKbl3uZeVaAFz
AewTE91o0IKEEuGzcfeYXyVF+r8kV4lCsQMvR/ROAR/LZzPZY0ajHG/gn4Ig+zoM
xqqS5vl32El7SjsCVgmt4JV29lS6UZtCEBeav8w3dIUDLgGBmXwLN3GTL0xqXYBG
YJT0ZKm/8Ixk8RcPQA/dnzNdSXavn71a5Vc61bNAUs+U10e1ctOvRoxZAe+EdNYz
W7SwNEPNgVWcxCkDJJ9gwiha67oKrVoMmfAfJMa6INfjEUKoBV/4UwpyvjgYYzBf
j/SDNem/APQfnKjz9yfi9uNCqoh2jYC9l9O9Pyj1nhoVDavOnp+wu1N9uEx8Pe/I
MJ5fA6jpAoGBAMzSDMqL3T8I8XxoWcfq2NRDVJIUJv4P0fr2hbiV8pVbiw5cUs0b
/Nv+3/uFuZEPMWKKN1F/IylUPAUipYrGbcjOd2XY+AtASxXzv55Q0KHp6CIP7FT6
AHb5XKO2s0YnrsL54YMImhRjmDl14C33hT4VS1v05Khd3XHAWyMfdk9zAoGBAOK2
F9zpg08ZwOjbEH1aUpd/+mCXTr0kLsfYwWFQVBc3rJ4m24BB7rBf35d1ixVLUktL
lhCJZjeiDKeVKCh1Tzc9dVRpxV1d2vTIUtcyPooIMY4MrS+z6Oxg95hDxEegbdY7
uEYa7SHLWKjEIS6VBo2VXZ6hF6X8syZtqqSr0ttLAoGAVwqw6uazWFVpopAKD36L
NPGEICw2QePhPYDEZSQ8GiL0Hl83xPiu5aMT9qTmrnHBb/oC9jxMagTlGN2XcjlP
cHXlob+p8cYZ4rNabGI1t4la4BbaPWadCfKA3wYGe7rjdvKQVooySJXmnAyu/3ng
AvkztFmHTtHNCMlRMcTuF2cCgYEAivhOJmepyxohS1vFfuGYETAs3XrClGSSnIR8
/dcMxPKmyIdPNA62br1GRQSTjikOuAMMaPSgiOe31B41cJ+AQH9W5bi0d+gpaLVH
OoydE2W0YrvYiY5B8Gv8OgUIU1O/IHyZF7g3teh9X25iXLiTPMTbj3p2EZSWiK7e
1HRTG4MCgYEAyqqtPdQo7xhAlRVTHVGk8XShL9NNNWkl5kel/bb9CMkE5BrAnXYP
HOPS75ONXbiVKsvP/Kwr1KtxBM7ly4Hva+RCGZC7nTx19RrJczQs5WJ4QERB3olg
K77r8Yiz9vse71sCoN5uPb+rOMFT6/2WT9Tl0JYhtjYSBRo5aHi1pR0=
-----END RSA PRIVATE KEY-----
ricardopadilha commented 3 months ago

Usando a chave acima, você deveria conseguir fazer uma chamada usando o axios assim:

const axios = require('axios');
const https = require('https');

const response = await axios.get("https://br-app-gateway.gwmcloud.com/app-api/api/v1.0/vehicle/vehicleBasicsInfo", {
  params: {
    vin: '<vin>',
  },
  headers: {
    rs: '2',
    brand: '6',
    terminal: 'GW_APP_GWM',
    country: 'BR',
    language: 'pt_BR',
    accessToken: <accessToken>,
  },
  httpsAgent: new https.Agent({
    ciphers: "DEFAULT@SECLEVEL=0",
    cert: '<conteúdo de gwm_general.cer>',
    key: '<conteúdo da chave acima>',
    ca: '<conteúdo de gwm_root.cer>',
    rejectUnauthorized: false,
  })
ricardopadilha commented 3 months ago

Também é possível testar a API usando curl:

 curl --verbose \
 --cert $PWD/client.cer --key $PWD/client.key --cacert $PWD/root.cer \
 --ciphers 'DEFAULT@SECLEVEL=0' \
 -H 'rs: 2' \
 -H 'brand: 6' \
 -H 'terminal: GW_APP_GWM' \
 -H 'country: BR' \
 -H 'language: pt_BR' \
 -H 'accessToken: <access_token>' \
 'https://br-app-gateway.gwmcloud.com/app-api/api/v1.0/vehicle/vehicleBasicsInfo?vin=<vin>'
ipsBruno commented 3 months ago

Cara muito bom mesmo, eu passei horas tentando fazer a requisição sem aquela gambiarra do C# e naoc conseguia trabalhar nos parametros RSA em NodeJS

Até achei que seria impossível

ricardopadilha commented 2 months ago

Para futura referência, aqui vai um fiddle com o código que eu usei para gerar a chave privada: https://dotnetfiddle.net/T1aIor