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

     1  package pairing
     2  
     3  import (
     4  	"crypto/ed25519"
     5  	"errors"
     6  	"fmt"
     7  	"io"
     8  
     9  	"code.pfad.fr/gohmekit/tlv8"
    10  )
    11  
    12  type pairSetupRequest struct {
    13  	ktlvState
    14  	Method byte `tlv8:"kTLVType_Method"`
    15  
    16  	Identifier    []byte `tlv8:"kTLVType_Identifier"`
    17  	PublicKey     []byte `tlv8:"kTLVType_PublicKey"`
    18  	Proof         []byte `tlv8:"kTLVType_Proof"`
    19  	EncryptedData []byte `tlv8:"kTLVType_EncryptedData"`
    20  }
    21  
    22  func (srv *HTTPServer) pairSetup(conn *encryptableConn, r io.Reader) ([]byte, error) {
    23  	var req pairSetupRequest
    24  	err := tlv8.NewDecoder(r).Decode(&req)
    25  	if err != nil {
    26  		return nil, err
    27  	}
    28  
    29  	switch req.State {
    30  	case 1:
    31  		return srv.pairSetupStartResponse(conn, req)
    32  	case 3:
    33  		return srv.pairSetupVerifyResponse(conn, req)
    34  	case 5:
    35  		return srv.pairSetupExchangeResponse(conn, req)
    36  	default:
    37  		return nil, fmt.Errorf("unexpected state: %d", req.State)
    38  	}
    39  }
    40  
    41  func (srv *HTTPServer) pairSetupStartResponse(conn *encryptableConn, req pairSetupRequest) ([]byte, error) {
    42  	if req.Method != kTLVMethod_PairSetup {
    43  		return nil, fmt.Errorf("unsupported method: %d", req.Method)
    44  	}
    45  
    46  	if srv.Database.IsPaired() {
    47  		return ktlvError(2, kTLVError_Unavailable)
    48  	}
    49  
    50  	session, salt, err := srv.Device.SRPSession()
    51  	if err != nil {
    52  		return nil, err
    53  	}
    54  
    55  	conn.pairSetup.SRPSession = session
    56  	conn.pairSetup.SRPSharedSecret = nil
    57  
    58  	return tlv8.Marshal(struct {
    59  		ktlvState
    60  		Salt      []byte `tlv8:"kTLVType_Salt"`
    61  		PublicKey []byte `tlv8:"kTLVType_PublicKey"`
    62  	}{
    63  		ktlvState: ktlvState{2},
    64  		PublicKey: session.PublicKey(),
    65  		Salt:      salt,
    66  	})
    67  }
    68  
    69  func (srv *HTTPServer) pairSetupVerifyResponse(conn *encryptableConn, req pairSetupRequest) ([]byte, error) {
    70  	if conn.pairSetup.SRPSession == nil {
    71  		return nil, errors.New("shared secret has not been constructed yet")
    72  	}
    73  
    74  	iOSPublicKey := req.PublicKey
    75  	sessionKey, err := conn.pairSetup.SRPSession.PairSetupSharedSecret(iOSPublicKey)
    76  	if err != nil {
    77  		return nil, err
    78  	}
    79  
    80  	clientProof := req.Proof
    81  	serverProof, ok := conn.pairSetup.SRPSession.ExchangeProof(clientProof)
    82  	if !ok {
    83  		return ktlvError(4, kTLVError_Authentication)
    84  	}
    85  
    86  	conn.pairSetup.SRPSharedSecret = sessionKey
    87  
    88  	return tlv8.Marshal(struct {
    89  		ktlvState
    90  		Proof []byte `tlv8:"kTLVType_Proof"`
    91  	}{
    92  		ktlvState: ktlvState{4},
    93  		Proof:     serverProof,
    94  	})
    95  }
    96  
    97  func (srv *HTTPServer) pairSetupExchangeResponse(conn *encryptableConn, req pairSetupRequest) ([]byte, error) {
    98  	if len(conn.pairSetup.SRPSharedSecret) == 0 {
    99  		return nil, errors.New("session key has not been constructed yet")
   100  	}
   101  
   102  	aead, err := conn.pairSetup.SRPSharedSecret.AEAD()
   103  	if err != nil {
   104  		return nil, err
   105  	}
   106  
   107  	encryptedData := req.EncryptedData
   108  	decryptedData, err := aead.Open(encryptedData[:0], paddedNonce("PS-Msg05"), encryptedData, nil)
   109  	if err != nil {
   110  		return ktlvError(6, kTLVError_Authentication)
   111  	}
   112  
   113  	type subTLV struct {
   114  		Identifier []byte `tlv8:"kTLVType_Identifier"`
   115  		PublicKey  []byte `tlv8:"kTLVType_PublicKey"`
   116  		Signature  []byte `tlv8:"kTLVType_Signature"`
   117  	}
   118  	var decodedData subTLV
   119  	err = tlv8.Unmarshal(decryptedData, &decodedData)
   120  	if err != nil {
   121  		return nil, fmt.Errorf("could not decode encrypted data: %w", err)
   122  	}
   123  
   124  	iOSDevicePairingID := decodedData.Identifier
   125  	iOSDeviceLTPK := decodedData.PublicKey
   126  	iOSDeviceSignature := decodedData.Signature
   127  
   128  	hash, err := conn.pairSetup.SRPSharedSecret.ControllerSign()
   129  	if err != nil {
   130  		return nil, fmt.Errorf("could not decode encrypted data: %w", err)
   131  	}
   132  
   133  	var iOSDeviceInfo []byte
   134  	iOSDeviceInfo = append(iOSDeviceInfo, hash...)
   135  	iOSDeviceInfo = append(iOSDeviceInfo, iOSDevicePairingID...)
   136  	iOSDeviceInfo = append(iOSDeviceInfo, iOSDeviceLTPK...)
   137  
   138  	if !ed25519.Verify(iOSDeviceLTPK, iOSDeviceInfo, iOSDeviceSignature) {
   139  		return ktlvError(6, kTLVError_Authentication)
   140  	}
   141  
   142  	err = srv.Database.AddLongTermPublicKey(Controller{PairingID: iOSDevicePairingID, LongTermPublicKey: iOSDeviceLTPK})
   143  	if err != nil {
   144  		return nil, fmt.Errorf("could not decode encrypted data: %w", err)
   145  	}
   146  
   147  	hash, err = conn.pairSetup.SRPSharedSecret.AccessorySign()
   148  	if err != nil {
   149  		return nil, fmt.Errorf("could not decode encrypted data: %w", err)
   150  	}
   151  
   152  	var accessoryInfo []byte
   153  	accessoryInfo = append(accessoryInfo, hash...)
   154  	accessoryInfo = append(accessoryInfo, srv.Device.PairingID()...)
   155  	accessoryInfo = append(accessoryInfo, srv.Device.OwnLongTermPublicKey()...)
   156  
   157  	accessorySignature, err := srv.Device.Ed25519Sign(accessoryInfo)
   158  	if err != nil {
   159  		return nil, fmt.Errorf("could not decode encrypted data: %w", err)
   160  	}
   161  
   162  	cleartextData, err := tlv8.Marshal(subTLV{
   163  		Identifier: srv.Device.PairingID(),
   164  		PublicKey:  srv.Device.OwnLongTermPublicKey(),
   165  		Signature:  accessorySignature,
   166  	})
   167  	if err != nil {
   168  		return nil, err
   169  	}
   170  
   171  	encryptedData = aead.Seal(cleartextData[:0], paddedNonce("PS-Msg06"), cleartextData, nil)
   172  
   173  	conn.pairSetup.SRPSession = nil
   174  	conn.pairSetup.SRPSharedSecret = nil
   175  
   176  	srv.Logger.Log("completed", "pair-setup", "id", string(iOSDevicePairingID))
   177  
   178  	return tlv8.Marshal(struct {
   179  		ktlvState
   180  		EncryptedData []byte `tlv8:"kTLVType_EncryptedData"`
   181  	}{
   182  		ktlvState:     ktlvState{6},
   183  		EncryptedData: encryptedData,
   184  	})
   185  }