code.pfad.fr/gohmekit@v0.2.1/pairing/pair_verify.go (about)

     1  package pairing
     2  
     3  import (
     4  	"crypto/ed25519"
     5  	"errors"
     6  	"fmt"
     7  	"io"
     8  
     9  	"code.pfad.fr/gohmekit/pairing/crypto"
    10  	"code.pfad.fr/gohmekit/tlv8"
    11  )
    12  
    13  type pairVerifyRequest struct {
    14  	ktlvState
    15  
    16  	PublicKey     []byte `tlv8:"kTLVType_PublicKey"`
    17  	EncryptedData []byte `tlv8:"kTLVType_EncryptedData"`
    18  }
    19  
    20  func (srv *HTTPServer) pairVerify(conn *encryptableConn, r io.Reader) ([]byte, error) {
    21  	var req pairVerifyRequest
    22  	err := tlv8.NewDecoder(r).Decode(&req)
    23  	if err != nil {
    24  		return nil, err
    25  	}
    26  
    27  	switch req.State {
    28  	case 1:
    29  		return srv.pairVerifyStartResponse(conn, req)
    30  	case 3:
    31  		return srv.pairVerifyFinishResponse(conn, req)
    32  	default:
    33  		return nil, fmt.Errorf("unexpected state: %d", req.State)
    34  	}
    35  }
    36  
    37  func (srv *HTTPServer) pairVerifyStartResponse(conn *encryptableConn, req pairVerifyRequest) ([]byte, error) {
    38  	key, err := crypto.NewKeyOnCurve25519()
    39  	if err != nil {
    40  		return nil, err
    41  	}
    42  
    43  	conn.pairVerify.ownPublicKey = key.PublicKey()
    44  	conn.pairVerify.iOSDevicePublicKey = req.PublicKey
    45  
    46  	conn.pairVerify.SharedSecret, err = key.PairVerifySharedSecret(conn.pairVerify.iOSDevicePublicKey)
    47  	if err != nil {
    48  		return nil, err
    49  	}
    50  
    51  	var accessoryInfo []byte
    52  	accessoryInfo = append(accessoryInfo, key.PublicKey()...)
    53  	accessoryInfo = append(accessoryInfo, srv.Device.PairingID()...)
    54  	accessoryInfo = append(accessoryInfo, conn.pairVerify.iOSDevicePublicKey...)
    55  
    56  	accessorySignature, err := srv.Device.Ed25519Sign(accessoryInfo)
    57  	if err != nil {
    58  		return nil, err
    59  	}
    60  
    61  	cleartextData, err := tlv8.Marshal(struct {
    62  		Identifier []byte `tlv8:"kTLVType_Identifier"`
    63  		Signature  []byte `tlv8:"kTLVType_Signature"`
    64  	}{
    65  		Identifier: srv.Device.PairingID(),
    66  		Signature:  accessorySignature,
    67  	})
    68  	if err != nil {
    69  		return nil, err
    70  	}
    71  
    72  	aead, err := crypto.PairVerifyAEAD(conn.pairVerify.SharedSecret)
    73  	if err != nil {
    74  		return nil, err
    75  	}
    76  
    77  	encryptedData := aead.Seal(cleartextData[:0], paddedNonce("PV-Msg02"), cleartextData, nil)
    78  
    79  	return tlv8.Marshal(struct {
    80  		ktlvState
    81  		PublicKey     []byte `tlv8:"kTLVType_PublicKey"`
    82  		EncryptedData []byte `tlv8:"kTLVType_EncryptedData"`
    83  	}{
    84  		ktlvState:     ktlvState{2},
    85  		PublicKey:     key.PublicKey(),
    86  		EncryptedData: encryptedData,
    87  	})
    88  }
    89  
    90  func (srv *HTTPServer) pairVerifyFinishResponse(conn *encryptableConn, req pairVerifyRequest) ([]byte, error) {
    91  	if len(conn.pairVerify.SharedSecret) == 0 {
    92  		return nil, errors.New("shared secret has not been constructed yet")
    93  	}
    94  
    95  	aead, err := crypto.PairVerifyAEAD(conn.pairVerify.SharedSecret)
    96  	if err != nil {
    97  		return nil, err
    98  	}
    99  
   100  	encryptedData := req.EncryptedData
   101  	decryptedData, err := aead.Open(encryptedData[:0], paddedNonce("PV-Msg03"), encryptedData, nil)
   102  	if err != nil {
   103  		return ktlvError(4, kTLVError_Authentication)
   104  	}
   105  
   106  	var decodedData struct {
   107  		Identifier []byte `tlv8:"kTLVType_Identifier"`
   108  		Signature  []byte `tlv8:"kTLVType_Signature"`
   109  	}
   110  	err = tlv8.Unmarshal(decryptedData, &decodedData)
   111  	if err != nil {
   112  		return nil, fmt.Errorf("could not decode encrypted data: %w", err)
   113  	}
   114  
   115  	iOSDevicePairingID := decodedData.Identifier
   116  	iOSDeviceSignature := decodedData.Signature
   117  
   118  	iOSDeviceLTPK, err := srv.Database.GetLongTermPublicKey(iOSDevicePairingID)
   119  	if err != nil {
   120  		return nil, err
   121  	}
   122  
   123  	var iOSDeviceInfo []byte
   124  	iOSDeviceInfo = append(iOSDeviceInfo, conn.pairVerify.iOSDevicePublicKey...)
   125  	iOSDeviceInfo = append(iOSDeviceInfo, iOSDevicePairingID...)
   126  	iOSDeviceInfo = append(iOSDeviceInfo, conn.pairVerify.ownPublicKey...)
   127  
   128  	if !ed25519.Verify(iOSDeviceLTPK, iOSDeviceInfo, iOSDeviceSignature) {
   129  		return ktlvError(4, kTLVError_Authentication)
   130  	}
   131  
   132  	var sharedKey [32]byte
   133  	copy(sharedKey[:], conn.pairVerify.SharedSecret)
   134  
   135  	conn.pairVerify.ownPublicKey = nil
   136  	conn.pairVerify.iOSDevicePublicKey = nil
   137  	conn.pairVerify.SharedSecret = nil
   138  
   139  	srv.Logger.Log("completed", "pair-verify", "id", string(iOSDevicePairingID))
   140  
   141  	err = conn.StartEncryptedSession(sharedKey, true)
   142  	if err != nil {
   143  		return nil, err
   144  	}
   145  	return tlv8.Marshal(ktlvState{4})
   146  }