Skip to content

Commit

Permalink
Merge pull request #506 from wultra/develop
Browse files Browse the repository at this point in the history
Merge develop to master
  • Loading branch information
hvge authored Aug 31, 2023
2 parents d107956 + 71a720e commit 8336bb4
Show file tree
Hide file tree
Showing 122 changed files with 8,241 additions and 3,304 deletions.
11 changes: 11 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates

version: 2
updates:
- package-ecosystem: "maven"
directory: "/"
schedule:
interval: "weekly"
68 changes: 12 additions & 56 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
@@ -1,66 +1,22 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
name: "CodeQL"

on:
workflow_dispatch:
push:
branches: [develop, master]
branches: [ 'develop', 'master', 'releases/**' ]
pull_request:
# The branches below must be a subset of the branches above
branches: [develop]
branches: [ 'develop', 'master', 'releases/**' ]
schedule:
- cron: '0 2 * * 4'

jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest

strategy:
fail-fast: false
matrix:
# Override automatic language detection by changing the below list
# Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
language: ['java']
# Learn more...
# https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection

steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
fetch-depth: 2

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main

# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2

# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl

# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language

#- run: |
# make bootstrap
# make release

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
codeql-analysis:
uses: wultra/wultra-infrastructure/.github/workflows/codeql-analysis.yml@develop
secrets: inherit
with:
languages: "['java']"
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Use only 'java' to analyze code written in Java, Kotlin or both
# Use only 'javascript' to analyze code written in JavaScript, TypeScript or both
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
6 changes: 4 additions & 2 deletions .github/workflows/maven-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ on:
- 'test/ci'

jobs:
maven-deploy-push:
maven-deploy-jfrog:
if: ${{ github.event_name == 'push' }}
name: Deploy to jfrog
uses: wultra/wultra-infrastructure/.github/workflows/maven-deploy.yml@develop
Expand All @@ -45,4 +45,6 @@ jobs:
release_type: ${{ inputs.release_type }}
secrets:
username: ${{ secrets.MAVEN_CENTRAL_USERNAME }}
password: ${{ secrets.MAVEN_CENTRAL_PASSWORD }}
password: ${{ secrets.MAVEN_CENTRAL_PASSWORD }}
gpg_passphrase: ${{ secrets.OSSRH_GPG_SECRET_KEY_PASSWORD }}
gpg_key: ${{ secrets.OSSRH_GPG_SECRET_KEY }}
19 changes: 0 additions & 19 deletions .travis.yml

This file was deleted.

23 changes: 12 additions & 11 deletions docs/Activation-Status.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# Activation Status

PowerAuth Client may need to check for an activation status, so that it can determine if it should display UI for non-activated state (registration form), blocked state (how to unblock tutorial) or active state (login screen). To facilitate this use-case, PowerAuth Standard RESTful API publishes a [/pa/v3/activation/status](./Standard-RESTful-API.md#activation-status) endpoint.
PowerAuth Client may need to check for an activation status, so that it can determine if it should display UI for non-activated state (registration form), blocked state (how to unblock tutorial) or active state (login screen). To facilitate this use-case, PowerAuth Standard RESTful API publishes a [/pa/v3/activation/status](./Standard-RESTful-API#post-pav3activationstatus) endpoint.

## Flow of the Activation Status Check
Checking for an activation status is simple. Client needs to prepare a HTTP request with an activation ID and random `STATUS_CHALLENGE`. Server processes the request and sends back the response with activation status blob and random `STATUS_NONCE`. Activation status blob is an encrypted binary blob that encodes the activation status. Key `KEY_TRANSPORT` and `STATUS_IV` is used to encrypt the activation blob.

Checking for an activation status is simple. Client needs to prepare a HTTP request with an activation ID and random `STATUS_CHALLENGE`. Server processes the request and sends back the response with activation status blob and random `STATUS_NONCE`. Activation status blob is an encrypted binary blob that encodes activation status. Key `KEY_TRANSPORT` and `STATUS_IV` is used to encrypt the activation blob.
## Status Check Sequence

Following sequence diagram shows the activation status check in more detail.
The following sequence diagram shows the activation status check in more detail.

![Check Activation Status](./resources/images/sequence_activation_status.png)

Expand Down Expand Up @@ -37,19 +37,21 @@ Following sequence diagram shows the activation status check in more detail.
byte[] STATUS_IV = KeyConversion.getBytes(KDF_INTERNAL.derive(KEY_TRANSPORT_IV, STATUS_IV_DATA))
byte[] statusBlob = AES.decrypt(encryptedStatusBlob, STATUS_IV, KEY_TRANSPORT, "AES/CBC/NoPadding")
```

## Status Blob Format

When obtaining the activation status, application receives the binary status blob. Structure of the 32B long status blob is following:
When obtaining the activation status, application receives the binary status blob. Structure of the 32B long status blob is the following (without newlines):

```
0xDEC0DED1 1B:${STATUS} 1B:${CURRENT_VERSION} 1B:${UPGRADE_VERSION} 5B:${RESERVED} 1B:${CTR_BYTE} 1B:${FAIL_COUNT} 1B:${MAX_FAIL_COUNT} 1B:${CTR_LOOK_AHEAD} 16B:${CTR_DATA_HASH}
0xDEC0DED1 1B:${STATUS} 1B:${CURRENT_VERSION} 1B:${UPGRADE_VERSION}
5B:${RESERVED} 1B:${CTR_BYTE} 1B:${FAIL_COUNT} 1B:${MAX_FAIL_COUNT}
1B:${CTR_LOOK_AHEAD} 16B:${CTR_DATA_HASH}
```

where:

- The first 4 bytes (`0xDE 0xC0 0xDE 0xD1`) are basically a fixed prefix.
- Note that the last byte of this constant also represents the version of the status blob format. If we decide to change the status blob significantly, then the value will be changed to `0xD2`, `0xD3`, etc...
- Note that the last byte of this constant also represents the version of the status blob format. If we decide to change the status blob significantly, then the value will be changed to `0xD2`, `0xD3`, etc.
- `${STATUS}` - A status of the activation record, it can be one of following values:
- `0x01 - CREATED`
- `0x02 - PENDING_COMMIT`
Expand All @@ -61,16 +63,15 @@ where:
- `0x03` - PowerAuth protocol version `3.x`
- `${UPGRADE_VERSION}` - 1 byte representing maximum protocol version supported by the PowerAuth Server. The set of possible values is identical to `${CURRENT_VERSION}`
- `${RESERVED}` - 5 bytes reserved for the future use.
- `${CTR_BYTE}` - 1 byte representing least significant byte from current value of counter, calculated as:
- `${CTR_BYTE}` - 1 byte representing the least significant byte from current value of counter, calculated as:
```java
byte CTR_BYTE = (byte)(CTR & 0xFF);
```
- `${FAIL_COUNT}` - 1 byte representing information about the number of failed attempts at the moment.
- `${MAX_FAIL_COUNT}` - 1 byte representing information about the maximum allowed number of failed attempts.
- `${CTR_LOOK_AHEAD}` - 1 byte representing constant for a look ahead window, used on the server to validate the signature.
- `${CTR_DATA_HASH}` - 16 bytes containing hash from current value of hash-based counter:
- `${CTR_DATA_HASH}` - 16 bytes containing hash from current value of a hash-based counter:
```java
SecretKey KEY_TRANSPORT_CTR = KDF.derive(KEY_TRANSPORT, 4000);
byte[] CTR_DATA_HASH = KeyConversion.getBytes(KDF_INTERNAL.derive(KEY_TRANSPORT_CTR, CTR_DATA));
```

145 changes: 145 additions & 0 deletions docs/Activation-via-Activation-Code.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
# Activation via Activation Code

The most straight forward activation type is "activation via the activation code". The activation code is a random one-time token value with limited time span associated with the particular user. Typically, the activation code is displayed as a QR code in the Internet banking, at branch kiosk, or ATM, or - as a less secure but more convenient alternative - it can be sent via SMS message or e-mail.

## Example User Flow

From the user perspective, activation via activation code is performed as a sequence of steps in the mobile app and Activation Code Delivery Application (i.e., in web Internet banking). The following steps (with possible user interface alterations) should be performed:

### Activation Code Delivery Application

The following diagram shows example steps in the Internet banking as an example application. You can apply similar principles to other Activation Code Delivery Applications, such as branch kiosk.

![Activation - Web UI Flow](./resources/images/ui_internetbanking_activation_web.png)


### Mobile Application

The following diagram shows example steps in the mobile banking app.

![Activation - Mobile UI Flow](./resources/images/ui_internetbanking_activation_mobile.png)

## Sequence Diagrams

The sequence diagrams below explain the PowerAuth key exchange during the activation via activation code. It shows how an app with PowerAuth Mobile SDK, Enrollment Server, Activation Code Delivery Application and PowerAuth Server play together in order to establish a shared secret between the client mobile application and the PowerAuth Server.

For the sake of the simplicity, we have split the process into three diagrams.

### Activation Initialization

This diagram shows how the Activation Code Delivery Application requests the activation data from the PowerAuth Server. The process is initiated by the Activation Code Delivery Application (for example, the Internet banking in the web browser) and it also ends here: by displaying the activation data so that they can be entered in the mobile app and passed to the PowerAuth Mobile SDK.

![Activation Initialization](./resources/images/sequence_activation_init.png)

#### Process Description

1. The Activation Code Delivery Application requests a new activation for a given user.

1. PowerAuth Server generates an `ACTIVATION_ID`, `ACTIVATION_CODE`, `CTR_DATA` - an initial value for hash based counter, and a key pair `(KEY_SERVER_PRIVATE, KEY_SERVER_PUBLIC)`. Server also computes a signature `ACTIVATION_SIGNATURE` of `ACTIVATION_CODE` using servers master private key `KEY_SERVER_MASTER_PRIVATE`.
```java
String ACTIVATION_ID = Generator.randomUUID()
String ACTIVATION_CODE = Generator.randomActivationCode() // must be unique among records in CREATED and PENDING_COMMIT states
byte[] CTR_DATA = Generator.randomBytes(16)
KeyPair keyPair = KeyGenerator.randomKeyPair()
PrivateKey KEY_SERVER_PRIVATE = keyPair.getPrivate()
PublicKey KEY_SERVER_PUBLIC = keyPair.getPublic()
byte[] DATA = ByteUtils.encode(ACTIVATION_CODE)
byte[] ACTIVATION_SIGNATURE = ECDSA.sign(DATA, KEY_SERVER_MASTER_PRIVATE)
```

1. Record associated with given `ACTIVATION_ID` is now in `CREATED` state.

1. Activation Code Delivery Application receives an `ACTIVATION_CODE` and `ACTIVATION_SIGNATURE` (optional) and displays these information visually in the front-end so that a user can rewrite them in a mobile app with PowerAuth Mobile SDK.

### Key Exchange

This diagram shows how public keys are exchanged between the PowerAuth Mobile SDK and PowerAuth Server, and how the master shared secret and PowerAuth Standard Keys are derived.

<!-- begin box info -->
The Activation Code Delivery Application plays no active role in the process of a key exchange.
<!-- end -->

![Activation Key Exchange](./resources/images/sequence_activation_prepare.png)

#### Process Description

1. User enters the `ACTIVATION_CODE` and `ACTIVATION_SIGNATURE` (optional) in the app with PowerAuth Mobile SDK. The entry can be manual or using a QR code with activation data.

1. PowerAuth Mobile SDK verifies the `ACTIVATION_SIGNATURE` against `ACTIVATION_CODE` using `KEY_SERVER_MASTER_PUBLIC` and if the signature matches, it proceeds.
```java
byte[] DATA = ByteUtils.encode(ACTIVATION_CODE)
boolean isOK = ECDSA.verify(DATA, ACTIVATION_SIGNATURE, KEY_SERVER_MASTER_PUBLIC)
```

1. PowerAuth Mobile SDK generates its key pair `(KEY_DEVICE_PRIVATE, KEY_DEVICE_PUBLIC)`.
```java
KeyPair keyPair = KeyGenerator.randomKeyPair()
PrivateKey KEY_DEVICE_PRIVATE = keyPair.getPrivate()
PublicKey KEY_DEVICE_PUBLIC = keyPair.getPublic()
```

1. PowerAuth Mobile SDK encrypts the payload containing `KEY_DEVICE_PUBLIC` with an application scoped ECIES (level 2, `sh1="/pa/activation"`). Let's call the result of this step as `ACTIVATION_DATA`.

1. PowerAuth Mobile SDK encrypts payload containing `ACTIVATION_DATA` and `ACTIVATION_CODE` with an application scoped ECIES (level 1, `sh1="/pa/generic/application"`) and sends HTTPS request to the `/pa/v3/activation/create` endpoint.

1. Enrollment Server decrypts the ECIES envelope, with an application scoped ECIES (level 1, `sh1="/pa/generic/application"`) and calls PowerAuth Server with `ACTIVATION_DATA`. At this step, the `ACTIVATION_CODE` is be used to identify the pending activation.

1. PowerAuth Server receives `ACTIVATION_CODE` and `ACTIVATION_DATA` from Enrollment Server. The `ACTIVATION_CODE` identifies the record for a pending activation. If the record is unknown, then server returns a generic error.

1. PowerAuth Server decrypts `ACTIVATION_DATA` using an application scoped ECIES (level 2, `sh1="/pa/activation"`) and stores `KEY_DEVICE_PUBLIC` at given record.

1. PowerAuth Server generates its key pair `(KEY_SERVER_PRIVATE, KEY_SERVER_PUBLIC)`.
```java
KeyPair keyPair = KeyGenerator.randomKeyPair()
PrivateKey KEY_SERVER_PRIVATE = keyPair.getPrivate()
PublicKey KEY_SERVER_PUBLIC = keyPair.getPublic()
```

1. PowerAuth Server uses `KEY_DEVICE_PUBLIC` and `KEY_SERVER_PRIVATE` to deduce `KEY_MASTER_SECRET` using ECDH.
```java
KEY_MASTER_SECRET = ByteUtils.convert32Bto16B(ECDH.phase(KEY_SERVER_PRIVATE, KEY_DEVICE_PUBLIC))
```

1. PowerAuth Server changes the record status to `PENDING_COMMIT`.

1. PowerAuth Server encrypts response, containing `ACTIVATION_ID`, `CTR_DATA`, `KEY_SERVER_PUBLIC` with the same key as was used for ECIES level 2 decryption. This data is one more time encrypted by Enrollment Server, with the same key from ECIES level 1, and the response is sent to the PowerAuth Client.

1. PowerAuth Mobile SDK decrypts the response with both levels of ECIES, in the right order and receives `ACTIVATION_ID`, `KEY_SERVER_PUBLIC`, `CTR_DATA` and stores all that values locally in the volatile memory on the device.

1. PowerAuth Mobile SDK uses `KEY_DEVICE_PRIVATE` and `KEY_SERVER_PUBLIC` to deduce `KEY_MASTER_SECRET` using ECDH.
```java
KEY_MASTER_SECRET = ByteUtils.convert32Bto16B(ECDH.phase(KEY_DEVICE_PRIVATE, KEY_SERVER_PUBLIC))
```

### Activation Commit

Finally, the last diagram shows how the Activation Code Delivery Application proactively checks the status of the activation and allows its completion by committing the activation record. A PowerAuth Mobile SDK plays a very little role in this step. It only allows showing a public key fingerprint in the mobile app to the user so that the key exchange can be visually confirmed before committing the activation.

![Activation Commit](./resources/images/sequence_activation_commit.png)

#### Process Description

1. PowerAuth Mobile SDK displays `H_K_DEVICE_PUBLIC`, so that a user can visually verify the device public key correctness by comparing the `H_K_DEVICE_PUBLIC` value displayed in the Master Front-End Application.
```java
byte[] activationIdBytes = ByteUtils.encode(ACTIVATION_ID)
byte[] fingerprintBytes = ByteUtils.concat(K_DEVICE_PUBLIC_BYTES, activationIdBytes, K_SERVER_PUBLIC_BYTES)
byte[] truncatedBytes = ByteUtils.truncate(Hash.sha256(fingerprintBytes), 4)
int H_K_DEVICE_PUBLIC = ByteUtils.getInt(truncatedBytes) & 0x7FFFFFFF) % (10 ^ 8)
```
<!-- begin box info -->
Note: Client and server should allow checking the public key fingerprint before committing the activation. This is necessary so that user can verify the exchanged information in order to detect the MITM attack.
<!-- end -->

1. Activation Code Delivery Application allows completion of the activation. For example, it may ask the user to enter an OTP code delivered via an SMS message. Activation Code Delivery Application commits the activation by calling the `/pa/v3/activation/commit` service on PowerAuth Server.

1. Record associated with given `ACTIVATION_ID` is now in `ACTIVE` state.

## Related Topics

- [Activation Code Format](Activation-Code.md)
- [Activation via Recovery Code](./Activation-via-Recovery-Code.md)
- [Activation via Custom Credentials](./Activation-via-Custom-Credentials.md)
- [Checking Activation Status](./Activation-Status.md)
- [Key Derivation](./Key-derivation.md)
- [Additional Activation OTP](Additional-Activation-OTP.md)

Loading

0 comments on commit 8336bb4

Please sign in to comment.