#android #x509
#Android #x509
Вопрос:
Мне нужно проверить сертификаты, сгенерированные процессом аттестации ключей Android на сервере, однако у меня пока нет доступа к реальному устройству.
Как я могу сгенерировать сертификат X.509 с полями расширения, аналогичными тем, которые я должен получить с реального устройства?
Очевидно, что корневой сертификат будет самоподписанным.
Есть примеры в https://github.com/google/android-key-attestation/tree/master/server/examples Как сгенерировать те же сертификаты с моими значениями?
Я предпочитаю Java и Go на стороне сервера.
Ответ №1:
Нет другого способа сгенерировать настоящие сертификаты, подписанные Google, кроме использования реального устройства.
В целях тестирования можно сгенерировать сертификаты Android с теми же значениями, что и в процессе аттестации ключей Android, однако подписанные другим корневым сертификатом.
Ожидаемая структура сертификата
- Проверка аппаратных пар ключей с помощью аттестации ключей
- Аттестация ключа и идентификатора: схема данных расширения сертификата
- Образец аттестации ключей Android
Приведенный ниже код: (1) Считывает корневой сертификат Google из файла google-root-ca/google-1.pem
и использует его в качестве шаблона для создания нового сертификата с тем же содержимым. (2) Создает сертификат Android с аппаратно подтвержденным идентификатором, подписанным корневым сертификатом, сгенерированным на шаге (1)
package main
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/asn1"
"encoding/pem"
"io/ioutil"
"math/big"
"time"
)
func main() {
rootCACertBytes, rootCAPrivKey, err := createCARoot()
if err != nil {
panic(err)
}
rootCACert, err := x509.ParseCertificate(rootCACertBytes)
if err != nil {
panic(err)
}
androidCertBytes, err := createAndroidKeystoreKey(rootCACert, rootCAPrivKey)
if err != nil {
panic(err)
}
err = printCertInPEM(rootCACertBytes, "CA.pem")
if err != nil {
panic(err)
}
err = printCertInPEM(androidCertBytes, "android.pem")
if err != nil {
panic(err)
}
}
func createCARoot() ([]byte, *rsa.PrivateKey, error) {
privKey, err := rsa.GenerateKey(rand.Reader, 4096)
if err != nil {
return nil, nil, err
}
certTemplate, err := readGoogleRootCA()
if err != nil {
return nil, nil, err
}
cert, err := x509.CreateCertificate(rand.Reader, certTemplate, certTemplate, privKey.Public(), privKey)
if err != nil {
return nil, nil, err
}
return cert, privKey, nil
}
func randomSerialNumber() (*big.Int, error) {
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
return rand.Int(rand.Reader, serialNumberLimit)
}
func readGoogleRootCA() (*x509.Certificate, error) {
pemBytes, err := ioutil.ReadFile("google-root-ca/google-1.pem")
if err != nil {
return nil, err
}
decoded, rest := pem.Decode(pemBytes)
_ = rest
return x509.ParseCertificate(decoded.Bytes)
}
func printCertInPEM(certBytes []byte, outFile string) error {
return ioutil.WriteFile(outFile, pem.EncodeToMemory(
amp;pem.Block{Type: "CERTIFICATE", Bytes: certBytes}), 0644)
}
var androidKeyAttestationOID = []int{1, 3, 6, 1, 4, 1, 11129, 2, 1, 17}
func createAndroidKeystoreKey(rootCACert *x509.Certificate, rootCAKey *rsa.PrivateKey) ([]byte, error) {
privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
return nil, err
}
expiration := time.Now().AddDate(10, 0, 0)
serialNumber, err := randomSerialNumber()
if err != nil {
return nil, err
}
androidKeyAttestationExtension, err := CreateAndroidKeyAttestationExtension()
if err != nil {
return nil, err
}
certTemplate := amp;x509.Certificate{
SerialNumber: serialNumber,
Subject: pkix.Name{
CommonName: "Android Keystore Key",
},
NotBefore: time.Now(),
NotAfter: expiration,
KeyUsage: x509.KeyUsageDigitalSignature,
ExtraExtensions: []pkix.Extension{
{
Id: androidKeyAttestationOID,
Value: androidKeyAttestationExtension,
},
},
}
return x509.CreateCertificate(rand.Reader, certTemplate, rootCACert, privKey.Public(), rootCAKey)
}
func CreateAndroidKeyAttestationExtension() ([]byte, error) {
keyDesc := KeyDescription{
AttestationVersion: 0,
AttestationSecurityLevel: 1,
KeymasterVersion: 0,
KeymasterSecurityLevel: 0,
AttestationChallenge: []byte("abcdefg"),
UniqueID: []byte{},
SoftwareEnforced: AuthorizationList{
AttestationIDSerial: []byte{},
},
TeeEnforced: AuthorizationList{
AttestationIDSerial: []byte("00112233445566778899"),
},
}
return asn1.Marshal(keyDesc)
}
type KeyDescription struct {
AttestationVersion int
AttestationSecurityLevel asn1.Enumerated
KeymasterVersion int
KeymasterSecurityLevel asn1.Enumerated
AttestationChallenge []byte
UniqueID []byte
SoftwareEnforced AuthorizationList
TeeEnforced AuthorizationList
}
// Values are commented out as nil values fail
type AuthorizationList struct {
//Purpose []int `asn1:"tag:1,explicit,set,optional"`
//Algorithm int `asn1:"tag:2,explicit,optional"`
//KeySize int `asn1:"tag:3,explicit,optional"`
//Digest []int `asn1:"tag:5,explicit,set,optional"`
//Padding []int `asn1:"tag:6,explicit,set,optional"`
//EcCurve int `asn1:"tag:10,explicit,optional"`
//RsaPublicExponent int `asn1:"tag:200,explicit,optional"`
//RollbackResistance interface{} `asn1:"tag:303,explicit,optional"`
//ActiveDateTime int `asn1:"tag:400,explicit,optional"`
//OriginationExpireDateTime int `asn1:"tag:401,explicit,optional"`
//UsageExpireDateTime int `asn1:"tag:402,explicit,optional"`
//NoAuthRequired interface{} `asn1:"tag:503,explicit,optional"`
//UserAuthType int `asn1:"tag:504,explicit,optional"`
//AuthTimeout int `asn1:"tag:505,explicit,optional"`
//AllowWhileOnBody interface{} `asn1:"tag:506,explicit,optional"`
//TrustedUserPresenceRequired interface{} `asn1:"tag:507,explicit,optional"`
//TrustedConfirmationRequired interface{} `asn1:"tag:508,explicit,optional"`
//UnlockedDeviceRequired interface{} `asn1:"tag:509,explicit,optional"`
//AllApplications interface{} `asn1:"tag:600,explicit,optional"`
//ApplicationID interface{} `asn1:"tag:601,explicit,optional"`
//CreationDateTime int `asn1:"tag:701,explicit,optional"`
//Origin int `asn1:"tag:702,explicit,optional"`
//RootOfTrust RootOfTrust `asn1:"tag:704,explicit,optional"`
//OsVersion int `asn1:"tag:705,explicit,optional"`
//OsPatchLevel int `asn1:"tag:706,explicit,optional"`
//AttestationApplicationID []byte `asn1:"tag:709,explicit,optional"`
//AttestationIDBrand []byte `asn1:"tag:710,explicit,optional"`
//AttestationIDDevice []byte `asn1:"tag:711,explicit,optional"`
//AttestationIDProduct []byte `asn1:"tag:712,explicit,optional"`
AttestationIDSerial []byte `asn1:"tag:713,explicit,optional"`
//AttestationIDImei []byte `asn1:"tag:714,explicit,optional"`
//AttestationIDMeid []byte `asn1:"tag:715,explicit,optional"`
//AttestationIDManufacturer []byte `asn1:"tag:716,explicit,optional"`
//AttestationIDModel []byte `asn1:"tag:717,explicit,optional"`
//VendorPatchLevel int `asn1:"tag:718,explicit,optional"`
//BootPatchLevel int `asn1:"tag:719,explicit,optional"`
}
type RootOfTrust struct {
VerifiedBootKey []byte
DeviceLocked bool
VerifiedBootState VerifiedBootState
VerifiedBootHash []byte
}
type VerifiedBootState int
const (
Verified VerifiedBootState = iota
SelfSigned
Unverified
Failed
)
google-root-ca / google-1.pem
Сохраните содержимое второго корневого сертификата Google в google-root-ca/google-1.pem
used в приведенном выше коде.