// Unblind a signature and convert it into a token func (c Client) Unblind(storeLocal *types.ReissuePacketPrivate, signature []byte) ([]byte, error) { pubkey, err := new(signkeys.PublicKey).Unmarshal(storeLocal.PublicKey) if err != nil { return nil, err } params, err := jjm.NewBlindingFactors(&pubkey.PublicKey).Unmarshal(storeLocal.Factors) if err != nil { return nil, err } token, err := token.Unmarshal(storeLocal.Token) if err != nil { return nil, err } clearMessage := jjm.NewClearMessage(token.Hash()) blindSig, err := jjm.NewBlindSignature(&pubkey.PublicKey).Unmarshal(signature) blindClient := jjm.NewGenericBlindingClient(&pubkey.PublicKey, c.Curve) sig, _, err := blindClient.Unblind(params, clearMessage, blindSig) if err != nil { return nil, err } _, err = blindClient.Verify(sig, clearMessage) if err != nil { return nil, err } t := sig.(jjm.ClearSignature) token.AddSignature(&t) return token.Marshal() }
// Verify a given inputToken and return it's public key if it verifies. func (c *Client) Verify(inputToken []byte) (outputToken *TokenEntry, err error) { tokenUnmarshalled, err := token.Unmarshal(inputToken) if err != nil { c.LastError = err return nil, ErrFatal } keyid, owner := tokenUnmarshalled.Properties() pubkey, err := c.getPubKey(*keyid) if err != nil { return nil, err } // Check if it is expired. Duplicate. Keypool does that as well if pubkey.Expire < times.Now() { c.LastError = ErrExpireToken return nil, ErrFinal } // Get data from token, signature first signature := tokenUnmarshalled.GetSignature() tempSignature := jjm.NewClearSignature(&pubkey.PublicKey) tempSignature.PointR = signature.PointR tempSignature.ScalarS = signature.ScalarS tempSignature.ScalarR = signature.ScalarR // Get signature message clearMessage := jjm.NewClearMessage(tokenUnmarshalled.Hash()) // Verify the signature blindClient := jjm.NewGenericBlindingClient(&pubkey.PublicKey, c.packetClient.Curve) ok, err := blindClient.Verify(tempSignature, clearMessage) if err != nil || !ok { c.LastError = err return nil, ErrFinal } outputToken = &TokenEntry{ Hash: tokenUnmarshalled.Hash(), Token: inputToken, OwnerPubKey: owner, Usage: pubkey.Usage, Expire: pubkey.Expire, } return outputToken, nil }
// WalletToken gets a token from wallet that matches usage. // The token is reissued for owner if not nil. // If the token is a subscription-token and owner is not present, it // is stored and a "NeedReissue" error is returned. func (c *Client) WalletToken(usage string, owner *[ed25519.PublicKeySize]byte) (tokenHash []byte, err error) { newToken, params, pubkeyUsed, err := c.getTokenFromWallet(usage) if err != nil { return nil, err } // Cache token, params tokenUnmarshalled, err := token.Unmarshal(newToken) if err != nil { c.LastError = err return nil, ErrFatal } // Parse pubkeyUsed and add to keypool signerPubKey, err := new(signkeys.PublicKey).Unmarshal(pubkeyUsed) if err != nil { c.LastError = err return nil, ErrFatal } keyid, err := c.packetClient.Keypool.LoadKey(signerPubKey) if err != nil && err != keypool.ErrExists { c.LastError = err return nil, ErrFatal } c.packetClient.Keypool.SaveKey(*keyid) // If we have params this is not renewable renewable := false if params == nil || len(params) == 0 { renewable = true } else { // Unless the params state otherwise.... _, _, _, canReissue, err := types.UnmarshalParams(params) if err != nil { c.LastError = err return nil, ErrFatal } if canReissue { renewable = true } } //tokenUnmarshalled.KeyID ownerPubkey, ownerPrivkey := splitKey(c.walletKey) // Set tokenentry struct for storage tokenentry := TokenEntry{ Hash: tokenUnmarshalled.Hash(), Token: newToken, Params: params, OwnerPubKey: ownerPubkey, OwnerPrivKey: ownerPrivkey, Renewable: renewable, CanReissue: true, Usage: signerPubKey.Usage, Expire: signerPubKey.Expire, } err = c.walletStore.SetToken(tokenentry) // Cache current state if err != nil { c.LastError = err return nil, ErrFatal } if owner == nil && renewable == false { return tokenentry.Hash, ErrNeedReissue } // Reissue return c.ReissueToken(tokenentry.Hash, owner) }
// Reissue creates a request to be sent to the server to reissue a new token for an old token. oldOwner is the Private key for whoever owned oldToken. // NewOwner is the public key for whoever is to own the new token. Both can be nil. func (c Client) Reissue(oldTokenEnc []byte, oldOwner *[ed25519.PrivateKeySize]byte, newOwner *[ed25519.PublicKeySize]byte, params []byte) (toServer []byte, storeLocal *types.ReissuePacketPrivate, err error) { packet := new(types.ReissuePacket) packet.CallType = types.CallTypeReissue oldToken, err := token.Unmarshal(oldTokenEnc) if err != nil { return nil, nil, err } // Get info from parameters pubKey, pubParams, _, canReissue, err := types.UnmarshalParams(params) if err != nil { return nil, nil, err } // Verify that oldToken and params match oldKeyID := new([signkeys.KeyIDSize]byte) copy(oldKeyID[:], oldToken.KeyID) oldPubKey, err := c.Keypool.Lookup(*oldKeyID) if err != nil { return nil, nil, err } // Verify usage if oldPubKey.Usage != pubKey.Usage { return nil, nil, ErrParamMismatch } // Verify same service-guard if oldPubKey.Signer != pubKey.Signer { return nil, nil, ErrParamMismatch } // Add parameter publickey to keypool saveID, err := c.Keypool.LoadKey(pubKey) if err != nil && err != keypool.ErrExists { return nil, nil, err } // Save key to permanent storage if err == nil { c.Keypool.SaveKey(*saveID) } // Create new token data blindMessage, blindFactors, newToken, err := c.NewToken(pubKey, pubParams, newOwner) if err != nil { return nil, nil, err } packet.Token, err = oldToken.Marshal() if err != nil { return nil, nil, err } packet.BlindToken, err = blindMessage.Marshal() if err != nil { return nil, nil, err } packet.Params = params _, owner := oldToken.Properties() if owner != nil { if oldOwner == nil { return nil, nil, ErrMissingSigner } } packet.Sign(oldOwner) rpacket, err := packet.Marshal() if err != nil { return nil, nil, err } local := new(types.ReissuePacketPrivate) local.CanReissue = canReissue local.PublicKey, err = pubKey.Marshal() if err != nil { return nil, nil, err } local.Factors, err = blindFactors.Marshal() if err != nil { return nil, nil, err } local.Token, err = newToken.Marshal() if err != nil { return nil, nil, err } rhash := packet.Hash() local.RequestHash = rhash[:] local.Request = rpacket return rpacket, local, nil }
// ReissueToken reissues a token identified by tokenHash for owner. func (c *Client) ReissueToken(tokenHash []byte, ownerPubkey *[ed25519.PublicKeySize]byte) (newTokenHash []byte, err error) { var ownerPrivkey *[ed25519.PrivateKeySize]byte if !c.IsOnline() { c.LastError = ErrOffline return nil, ErrOffline } onlineGroup.Add(1) defer onlineGroup.Done() // Lock token against other use lockID := c.LockToken(tokenHash) if lockID == 0 { c.LastError = ErrLocked return nil, ErrRetry } defer c.UnlockToken(tokenHash) // Get client and token data issueClient, err := guardrpc.New(c.cacert) if err != nil { c.LastError = err return nil, ErrRetry } tokenEntry, err := c.walletStore.GetToken(tokenHash, lockID) if err != nil { c.LastError = err if err == ErrLocked { return nil, ErrRetry } return nil, ErrFatal } if tokenEntry.OwnerPrivKey == nil { c.LastError = ErrNotMine return nil, ErrFatal } tokenUnmarshalled, err := token.Unmarshal(tokenEntry.Token) if err != nil { c.LastError = err return nil, ErrFatal } keyid, _ := tokenUnmarshalled.Properties() key, err := c.packetClient.Keypool.Lookup(*keyid) if err != nil { c.LastError = err return nil, ErrFatal } // Test if we are communicating already if tokenEntry.ServerPacket == nil { // Test if we have params if tokenEntry.Params == nil { params, err := issueClient.GetParams(&key.Signer) if err != nil { c.LastError = err _, fatal, err := lookupError(err) if fatal { c.LastError = err return nil, ErrFinal } return nil, ErrRetry } tokenEntry.Params = params err = c.walletStore.SetToken(*tokenEntry) if err != nil { c.LastError = err return nil, ErrFatal } } // Generate new owner if no owner is specified if ownerPubkey == nil { ownerPubkey, ownerPrivkey, err = ed25519.GenerateKey(rand.Reader) if err != nil { c.LastError = err return nil, ErrFatal } tokenEntry.NewOwnerPrivKey = ownerPrivkey } tokenEntry.NewOwnerPubKey = ownerPubkey // Generate blinding packet serverPacket, blindingFactors, err := c.packetClient.Reissue(tokenEntry.Token, tokenEntry.OwnerPrivKey, tokenEntry.NewOwnerPubKey, tokenEntry.Params) if err != nil { c.LastError = err return nil, ErrFatal } // Marshall local, store packet and local in walletStore tokenEntry.BlindingFactors, err = blindingFactors.Marshal() if err != nil { c.LastError = err return nil, ErrFatal } tokenEntry.ServerPacket = serverPacket err = c.walletStore.SetToken(*tokenEntry) if err != nil { c.LastError = err return nil, ErrFatal } } // We have everything, make the call replyPacket, newPubkey, err := issueClient.Reissue(&key.Signer, tokenEntry.ServerPacket) if err != nil { c.LastError = err _, fatal, err := lookupError(err) if fatal { c.LastError = err return nil, ErrFinal } return nil, ErrRetry } c.walletStore.DelToken(tokenEntry.Hash) // Delete old token, it's invalid from here // Parse new pubkey and add to keypool signerPubKey, err := new(signkeys.PublicKey).Unmarshal(newPubkey) if err != nil { c.LastError = err return nil, ErrFatal } keyid, err = c.packetClient.Keypool.LoadKey(signerPubKey) if err != nil && err != keypool.ErrExists { c.LastError = err return nil, ErrFatal } c.packetClient.Keypool.SaveKey(*keyid) // Unblind the new token blindingFactors, err := new(types.ReissuePacketPrivate).Unmarshal(tokenEntry.BlindingFactors) if err != nil { c.LastError = err return nil, ErrFatal } newToken, err := c.packetClient.Unblind(blindingFactors, replyPacket) if err != nil { c.LastError = err return nil, ErrFatal } // Write it to database tokenUnmarshalled, err = token.Unmarshal(newToken) if err != nil { c.LastError = err return nil, ErrFatal } keyid, _ = tokenUnmarshalled.Properties() signerPubKey, err = c.packetClient.Keypool.Lookup(*keyid) if err != nil { c.LastError = err return nil, ErrFatal } tokenentryNew := TokenEntry{ Hash: tokenUnmarshalled.Hash(), Token: newToken, Params: nil, OwnerPubKey: tokenEntry.NewOwnerPubKey, OwnerPrivKey: tokenEntry.NewOwnerPrivKey, Renewable: tokenEntry.Renewable, CanReissue: tokenEntry.Renewable, Usage: signerPubKey.Usage, Expire: signerPubKey.Expire, } err = c.walletStore.SetToken(tokenentryNew) if err != nil { c.LastError = err return nil, ErrFatal } return tokenentryNew.Hash, nil }