Example #1
0
func (m *accountManager) GenerateOTP(ctx scope.Context, heim *proto.Heim, kms security.KMS, account proto.Account) (*proto.OTP, error) {
	m.b.Lock()
	defer m.b.Unlock()

	if m.b.otps == nil {
		m.b.otps = map[snowflake.Snowflake]*proto.OTP{}
	}

	old, ok := m.b.otps[account.ID()]
	if ok && old.Validated {
		return nil, proto.ErrOTPAlreadyEnrolled
	}

	otp, err := heim.NewOTP(account)
	if err != nil {
		return nil, err
	}

	m.b.otps[account.ID()] = otp
	return otp, nil
}
Example #2
0
func (b *AccountManagerBinding) GenerateOTP(ctx scope.Context, heim *proto.Heim, kms security.KMS, account proto.Account) (*proto.OTP, error) {
	encryptedKey, err := kms.GenerateEncryptedKey(OTPKeyType, "account", account.ID().String())
	if err != nil {
		return nil, err
	}

	key := encryptedKey.Clone()
	if err := kms.DecryptKey(&key); err != nil {
		return nil, err
	}

	iv, err := kms.GenerateNonce(OTPKeyType.BlockSize())
	if err != nil {
		return nil, err
	}

	t, err := b.DbMap.Begin()
	if err != nil {
		return nil, err
	}

	rawOTP, err := b.getRawOTP(t, account.ID())
	if err != nil && err != proto.ErrOTPNotEnrolled {
		rollback(ctx, t)
		return nil, err
	}
	if err == nil {
		if rawOTP.Validated {
			rollback(ctx, t)
			return nil, proto.ErrOTPAlreadyEnrolled
		}
		row := &OTP{AccountID: account.ID().String()}
		if _, err := t.Delete(row); err != nil {
			rollback(ctx, t)
			return nil, err
		}
	}

	otp, err := heim.NewOTP(account)
	if err != nil {
		rollback(ctx, t)
		return nil, err
	}

	digest, encryptedURI, err := security.EncryptGCM(&key, iv, []byte(otp.URI), nil)
	if err != nil {
		rollback(ctx, t)
		return nil, err
	}

	row := &OTP{
		AccountID:    account.ID().String(),
		IV:           iv,
		EncryptedKey: encryptedKey.Ciphertext,
		Digest:       digest,
		EncryptedURI: encryptedURI,
	}
	if err := t.Insert(row); err != nil {
		// TODO: this could fail in the case of a race condition
		// by the time that matters we should be on postgres 9.5 and using a proper upsert
		rollback(ctx, t)
		return nil, err
	}

	if err := t.Commit(); err != nil {
		return nil, err
	}

	return otp, nil
}