Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions play-services-constellation/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* SPDX-FileCopyrightText: 2025 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/

apply plugin: 'com.android.library'
apply plugin: 'maven-publish'
apply plugin: 'signing'

android {
namespace "com.google.android.gms.constellation"

compileSdkVersion androidCompileSdk
buildToolsVersion "$androidBuildVersionTools"

buildFeatures {
aidl = true
}

defaultConfig {
versionName version
minSdkVersion androidMinSdk
targetSdkVersion androidTargetSdk
}

compileOptions {
sourceCompatibility = 1.8
targetCompatibility = 1.8
}
}

apply from: '../gradle/publish-android.gradle'

description = 'microG implementation of play-services-constellation'

dependencies {
api project(':play-services-base')
api project(':play-services-basement')
api project(':play-services-tasks')
}

68 changes: 68 additions & 0 deletions play-services-constellation/core/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* SPDX-FileCopyrightText: 2025 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/

apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'maven-publish'
apply plugin: 'signing'

dependencies {
api project(':play-services-constellation')

implementation project(':play-services-base-core')
implementation project(':play-services-core-proto')
implementation project(':play-services-droidguard-core')
implementation project(':play-services-iid')
implementation project(':play-services-tasks-ktx')

implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutineVersion"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutineVersion"

implementation "androidx.lifecycle:lifecycle-service:$lifecycleVersion"
implementation "com.squareup.wire:wire-runtime:$wireVersion"
implementation "com.squareup.wire:wire-grpc-client:$wireVersion"
implementation "com.squareup.okhttp3:okhttp:4.12.0"
implementation "com.squareup.okhttp3:logging-interceptor:4.12.0"

// For entitlement library classes
implementation "com.google.guava:guava:31.1-android"
implementation "com.google.auto.value:auto-value-annotations:1.10.1"
annotationProcessor "com.google.auto.value:auto-value:1.10.1"
}

android {
namespace "org.microg.gms.constellation.core"

compileSdkVersion androidCompileSdk
buildToolsVersion "$androidBuildVersionTools"

defaultConfig {
versionName version
minSdkVersion androidMinSdk
targetSdkVersion androidTargetSdk
}

sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}

lintOptions {
disable 'MissingTranslation'
}

compileOptions {
sourceCompatibility = 1.8
targetCompatibility = 1.8
}

kotlinOptions {
jvmTarget = 1.8
}
}

apply from: '../../gradle/publish-android.gradle'

description = 'microG service implementation for play-services-constellation'
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.android.libraries.entitlement;

import android.net.Network;

import androidx.annotation.Nullable;

import com.android.libraries.entitlement.utils.UrlConnectionFactory;
import com.google.auto.value.AutoValue;

/**
* Carrier specific customization to be used in the service entitlement queries and operations.
*
* @see #ServiceEntitlement
*/
@AutoValue
public abstract class CarrierConfig {
/** Default value of {@link #timeoutInSec} if not set. */
public static final int DEFAULT_TIMEOUT_IN_SEC = 30;

public static final String CLIENT_TS_43_IMS_ENTITLEMENT = "client-IMS-Entitlement";
public static final String CLIENT_TS_43_COMPANION_ODSA = "client-Companion-ODSA";
public static final String CLIENT_TS_43_PRIMARY_ODSA = "client-Primary-ODSA";
public static final String CLIENT_TS_43_SERVER_ODSA = "client-Server-ODSA";

/** The carrier's entitlement server URL. See {@link Builder#setServerUrl}. */
public abstract String serverUrl();

/**
* Client-ts43 attribute. Used to set the User-Agent header in HTTP requests as defined in TS.43
* section 2.2.
*/
public abstract String clientTs43();

/** Returns {@code true} if HTTP POST, instead of GET, should be used for TS.43 requests. */
public abstract boolean useHttpPost();

/** Client side timeout for HTTP connection. See {@link Builder#setTimeoutInSec}. */
public abstract int timeoutInSec();

/** The {@link Network} used for HTTP connection. See {@link Builder#setNetwork}. */
@Nullable
public abstract Network network();

/** The factory to create connections. See {@link Builder#setUrlConnectionFactory}. */
@Nullable
public abstract UrlConnectionFactory urlConnectionFactory();

/** The EAP-AKA realm. See {@link Builder#setEapAkaRealm}. */
public abstract String eapAkaRealm();

/** Returns a new {@link Builder} object. */
public static Builder builder() {
return new AutoValue_CarrierConfig.Builder()
.setServerUrl("")
.setClientTs43("")
.setUseHttpPost(false)
.setTimeoutInSec(DEFAULT_TIMEOUT_IN_SEC)
.setEapAkaRealm("nai.epc");
}

/** Builder. */
@AutoValue.Builder
public abstract static class Builder {
public abstract CarrierConfig build();

/**
* Sets the carrier's entitlement server URL. If not set, will use {@code
* https://aes.mnc<MNC>.mcc<MCC>.pub.3gppnetwork.org} as defined in GSMA TS.43 section 2.1.
*/
public abstract Builder setServerUrl(String url);

/** Sets the Client-ts43 attribute. Used to set the User-Agent header in HTTP requests. */
public abstract Builder setClientTs43(String clientTs43);

/** Set to {@code true} to use HTTP POST instead of GET for TS.43 requests. */
public abstract Builder setUseHttpPost(boolean useHttpPost);

/**
* Sets the client side timeout for HTTP connection. Default to
* {@link DEFAULT_TIMEOUT_IN_SEC}.
*
* <p>This timeout is used by both {@link java.net.URLConnection#setConnectTimeout} and
* {@link java.net.URLConnection#setReadTimeout}.
*/
public abstract Builder setTimeoutInSec(int timeoutInSec);

/**
* Sets the {@link Network} used for HTTP connection. If not set, the device default network
* is used.
*/
public abstract Builder setNetwork(Network network);

/**
* If unset, the default Android API {@link java.net.URL#openConnection}
* would be used. This allows callers of the lib to choose the HTTP stack.
*/
public abstract Builder setUrlConnectionFactory(UrlConnectionFactory urlConnectionFactory);

/**
* Sets the realm for EAP-AKA. If unset, uses the standard "nai.epc" defined in 3GPP TS
* 23.003 clause 19.3.2.
*/
public abstract Builder setEapAkaRealm(String eapAkaRealm);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.android.libraries.entitlement;

import static com.android.libraries.entitlement.eapaka.EapAkaResponse.respondToEapAkaChallenge;

import android.content.Context;
import android.telephony.TelephonyManager;
import android.util.Log;

import androidx.annotation.Nullable;

import com.android.libraries.entitlement.eapaka.EapAkaApi;
import com.android.libraries.entitlement.eapaka.EapAkaChallenge;

/**
* Some utility methods used in EAP-AKA authentication in service entitlement, and could be
* helpful to other apps.
*/
public class EapAkaHelper {
private static final String TAG = "ServiceEntitlement";

private final Context mContext;
private final int mSimSubscriptionId;

EapAkaHelper(Context context, int simSubscriptionId) {
mContext = context;
mSimSubscriptionId = simSubscriptionId;
}

/**
* Factory method.
*
* @param context context of application
* @param simSubscriptionId the subscroption ID of the carrier's SIM on device. This indicates
* which SIM to retrieve IMEI/IMSI from and perform EAP-AKA
* authentication with. See
* {@link android.telephony.SubscriptionManager}
* for how to get the subscroption ID.
*/
public static EapAkaHelper getInstance(Context context, int simSubscriptionId) {
return new EapAkaHelper(context, simSubscriptionId);
}

/**
* Returns the root NAI for EAP-AKA authentication as per 3GPP TS 23.003 19.3.2, or
* {@code null} if failed. The result will be in the form:
*
* <p>{@code 0<IMSI>@nai.epc.mnc<MNC>.mcc<MCC>.3gppnetwork.org}
*/
@Nullable
public String getEapAkaRootNai() {
TelephonyManager telephonyManager =
mContext.getSystemService(TelephonyManager.class)
.createForSubscriptionId(mSimSubscriptionId);
return EapAkaApi.getImsiEap(
telephonyManager.getSimOperator(), telephonyManager.getSubscriberId(), "nai.epc");
}

/**
* Returns the EAP-AKA challenge response to the given EAP-AKA {@code challenge}, or
* {@code null} if failed.
*
* <p>Both the challange and response are base-64 encoded EAP-AKA message: refer to
* RFC 4187 Section 8.1 Message Format/RFC 3748 Session 4 EAP Packet Format.
*
* @deprecated use {@link getEapAkaResponse(String)} which additionally supports
* Synchronization-Failure case.
*/
@Deprecated
@Nullable
public String getEapAkaChallengeResponse(String challenge) {
EapAkaResponse eapAkaResponse = getEapAkaResponse(challenge);
return (eapAkaResponse == null)
? null
: eapAkaResponse.response(); // Would be null on synchronization failure
}

/**
* Returns the {@link EapAkaResponse} to the given EAP-AKA {@code challenge}, or
* {@code null} if failed.
*
* <p>Both the challange and response are base-64 encoded EAP-AKA message: refer to
* RFC 4187 Section 8.1 Message Format/RFC 3748 Session 4 EAP Packet Format.
*/
@Nullable
public EapAkaResponse getEapAkaResponse(String challenge) {
try {
EapAkaChallenge eapAkaChallenge = EapAkaChallenge.parseEapAkaChallenge(challenge);
com.android.libraries.entitlement.eapaka.EapAkaResponse eapAkaResponse =
respondToEapAkaChallenge(
mContext, mSimSubscriptionId, eapAkaChallenge, "nai.epc");
return new EapAkaResponse(
eapAkaResponse.response(), eapAkaResponse.synchronizationFailureResponse());
} catch (ServiceEntitlementException e) {
Log.i(TAG, "Failed to generate EAP-AKA response", e);
return null;
}
}

// Similar to .eapaka.EapAkaResponse but with simplfied API surface for external usage.
/** EAP-AKA response */
public static class EapAkaResponse {
// RFC 4187 Section 9.4 EAP-Response/AKA-Challenge
@Nullable private final String mResponse;
// RFC 4187 Section 9.6 EAP-Response/AKA-Synchronization-Failure
@Nullable private final String mSynchronizationFailureResponse;

private EapAkaResponse(
@Nullable String response, @Nullable String synchronizationFailureResponse) {
mResponse = response;
mSynchronizationFailureResponse = synchronizationFailureResponse;
}

/**
* Returns EAP-Response/AKA-Challenge, if authentication success.
* Otherwise {@code null}.
*/
@Nullable
public String response() {
return mResponse;
}

/**
* Returns EAP-Response/AKA-Synchronization-Failure, if synchronization failure detected.
* Otherwise {@code null}.
*/
@Nullable
public String synchronizationFailureResponse() {
return mSynchronizationFailureResponse;
}
}
}
Loading