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
1 change: 1 addition & 0 deletions data/init.sql
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ CREATE TABLE IF NOT EXISTS profiles(
kvm_enabled BOOLEAN NULL,
sol_enabled BOOLEAN NULL,
tls_signing_authority varchar(40) NULL,
tls_signing_authority_url varchar(128) NULL,
ieee8021x_profile_name citext,
FOREIGN KEY (ieee8021x_profile_name,tenant_id) REFERENCES ieee8021xconfigs(profile_name,tenant_id),
PRIMARY KEY (profile_name, tenant_id)
Expand Down
25 changes: 17 additions & 8 deletions src/data/postgres/tables/profiles.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ describe('profiles tests', () => {
kvmEnabled: true,
solEnabled: true,
tlsSigningAuthority: null,
tlsSigningAuthorityURL: null,
ieee8021xProfileName: null
} as any
db = new PostgresDb('')
Expand Down Expand Up @@ -120,6 +121,7 @@ describe('profiles tests', () => {
sol_enabled as "solEnabled",
p.tenant_id as "tenantId",
tls_signing_authority as "tlsSigningAuthority",
tls_signing_authority_url as "tlsSigningAuthorityURL",
p.xmin as "version",
ieee8021x_profile_name as "ieee8021xProfileName",
COALESCE(json_agg(json_build_object('profileName',wc.wireless_profile_name, 'priority', wc.priority)) FILTER (WHERE wc.wireless_profile_name IS NOT NULL), '[]') AS "wifiConfigs",
Expand All @@ -142,6 +144,7 @@ describe('profiles tests', () => {
kvm_enabled,
sol_enabled,
tls_signing_authority,
tls_signing_authority_url,
p.tenant_id,
ieee8021x_profile_name,
ip_sync_enabled,
Expand Down Expand Up @@ -178,6 +181,7 @@ describe('profiles tests', () => {
sol_enabled as "solEnabled",
p.tenant_id as "tenantId",
tls_signing_authority as "tlsSigningAuthority",
tls_signing_authority_url as "tlsSigningAuthorityURL",
p.xmin as "version",
ieee8021x_profile_name as "ieee8021xProfileName",
COALESCE(json_agg(json_build_object('profileName',wc.wireless_profile_name, 'priority', wc.priority)) FILTER (WHERE wc.wireless_profile_name IS NOT NULL), '[]') AS "wifiConfigs",
Expand All @@ -200,6 +204,7 @@ describe('profiles tests', () => {
kvm_enabled,
sol_enabled,
tls_signing_authority,
tls_signing_authority_url,
p.tenant_id,
ieee8021x_profile_name,
ip_sync_enabled,
Expand Down Expand Up @@ -285,8 +290,8 @@ describe('profiles tests', () => {
mebx_password, generate_random_mebx_password,
tags, dhcp_enabled, tls_mode,
user_consent, ider_enabled, kvm_enabled, sol_enabled,
tenant_id, tls_signing_authority, ieee8021x_profile_name, ip_sync_enabled, local_wifi_sync_enabled)
values($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19)`,
tenant_id, tls_signing_authority, tls_signing_authority_url, ieee8021x_profile_name, ip_sync_enabled, local_wifi_sync_enabled)
values($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20)`,
[
amtConfig.profileName,
amtConfig.activation,
Expand All @@ -304,6 +309,7 @@ describe('profiles tests', () => {
amtConfig.solEnabled,
amtConfig.tenantId,
amtConfig.tlsSigningAuthority,
amtConfig.tlsSigningAuthorityURL,
amtConfig.ieee8021xProfileName,
amtConfig.ipSyncEnabled,
amtConfig.localWifiSyncEnabled
Expand Down Expand Up @@ -335,8 +341,8 @@ describe('profiles tests', () => {
mebx_password, generate_random_mebx_password,
tags, dhcp_enabled, tls_mode,
user_consent, ider_enabled, kvm_enabled, sol_enabled,
tenant_id, tls_signing_authority, ieee8021x_profile_name, ip_sync_enabled, local_wifi_sync_enabled)
values($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19)`,
tenant_id, tls_signing_authority, tls_signing_authority_url, ieee8021x_profile_name, ip_sync_enabled, local_wifi_sync_enabled)
values($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20)`,
[
amtConfig.profileName,
amtConfig.activation,
Expand All @@ -354,6 +360,7 @@ describe('profiles tests', () => {
amtConfig.solEnabled,
amtConfig.tenantId,
amtConfig.tlsSigningAuthority,
amtConfig.tlsSigningAuthorityURL,
amtConfig.ieee8021xProfileName,
amtConfig.ipSyncEnabled,
amtConfig.localWifiSyncEnabled
Expand Down Expand Up @@ -397,8 +404,8 @@ describe('profiles tests', () => {
mebx_password=$6, generate_random_mebx_password=$7,
tags=$8, dhcp_enabled=$9, tls_mode=$10, user_consent=$13,
ider_enabled=$14, kvm_enabled=$15, sol_enabled=$16,
tls_signing_authority=$17, ieee8021x_profile_name=$18,
ip_sync_enabled=$19, local_wifi_sync_enabled=$20
tls_signing_authority=$17, tls_signing_authority_url=$18, ieee8021x_profile_name=$19,
ip_sync_enabled=$20, local_wifi_sync_enabled=$21
WHERE profile_name=$1 and tenant_id = $11 and xmin = $12`,
[
amtConfig.profileName,
Expand All @@ -418,6 +425,7 @@ describe('profiles tests', () => {
amtConfig.kvmEnabled,
amtConfig.solEnabled,
amtConfig.tlsSigningAuthority,
amtConfig.tlsSigningAuthorityURL,
amtConfig.ieee8021xProfileName,
amtConfig.ipSyncEnabled,
amtConfig.localWifiSyncEnabled
Expand All @@ -442,8 +450,8 @@ describe('profiles tests', () => {
mebx_password=$6, generate_random_mebx_password=$7,
tags=$8, dhcp_enabled=$9, tls_mode=$10, user_consent=$13,
ider_enabled=$14, kvm_enabled=$15, sol_enabled=$16,
tls_signing_authority=$17, ieee8021x_profile_name=$18,
ip_sync_enabled=$19, local_wifi_sync_enabled=$20
tls_signing_authority=$17, tls_signing_authority_url=$18, ieee8021x_profile_name=$19,
ip_sync_enabled=$20, local_wifi_sync_enabled=$21
WHERE profile_name=$1 and tenant_id = $11 and xmin = $12`,
[
amtConfig.profileName,
Expand All @@ -463,6 +471,7 @@ describe('profiles tests', () => {
amtConfig.kvmEnabled,
amtConfig.solEnabled,
amtConfig.tlsSigningAuthority,
amtConfig.tlsSigningAuthorityURL,
amtConfig.ieee8021xProfileName,
amtConfig.ipSyncEnabled,
amtConfig.localWifiSyncEnabled
Expand Down
14 changes: 10 additions & 4 deletions src/data/postgres/tables/profiles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ export class ProfilesTable implements IProfilesTable {
sol_enabled as "solEnabled",
p.tenant_id as "tenantId",
tls_signing_authority as "tlsSigningAuthority",
tls_signing_authority_url as "tlsSigningAuthorityURL",
p.xmin as "version",
ieee8021x_profile_name as "ieee8021xProfileName",
COALESCE(json_agg(json_build_object('profileName',wc.wireless_profile_name, 'priority', wc.priority)) FILTER (WHERE wc.wireless_profile_name IS NOT NULL), '[]') AS "wifiConfigs",
Expand All @@ -96,6 +97,7 @@ export class ProfilesTable implements IProfilesTable {
kvm_enabled,
sol_enabled,
tls_signing_authority,
tls_signing_authority_url,
p.tenant_id,
ieee8021x_profile_name,
ip_sync_enabled,
Expand Down Expand Up @@ -136,6 +138,7 @@ export class ProfilesTable implements IProfilesTable {
sol_enabled as "solEnabled",
p.tenant_id as "tenantId",
tls_signing_authority as "tlsSigningAuthority",
tls_signing_authority_url as "tlsSigningAuthorityURL",
p.xmin as "version",
ieee8021x_profile_name as "ieee8021xProfileName",
COALESCE(json_agg(json_build_object('profileName',wc.wireless_profile_name, 'priority', wc.priority)) FILTER (WHERE wc.wireless_profile_name IS NOT NULL), '[]') AS "wifiConfigs",
Expand All @@ -158,6 +161,7 @@ export class ProfilesTable implements IProfilesTable {
kvm_enabled,
sol_enabled,
tls_signing_authority,
tls_signing_authority_url,
p.tenant_id,
ieee8021x_profile_name,
ip_sync_enabled,
Expand Down Expand Up @@ -224,8 +228,8 @@ export class ProfilesTable implements IProfilesTable {
mebx_password, generate_random_mebx_password,
tags, dhcp_enabled, tls_mode,
user_consent, ider_enabled, kvm_enabled, sol_enabled,
tenant_id, tls_signing_authority, ieee8021x_profile_name, ip_sync_enabled, local_wifi_sync_enabled)
values($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19)`,
tenant_id, tls_signing_authority, tls_signing_authority_url, ieee8021x_profile_name, ip_sync_enabled, local_wifi_sync_enabled)
values($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20)`,
[
amtConfig.profileName,
amtConfig.activation,
Expand All @@ -243,6 +247,7 @@ export class ProfilesTable implements IProfilesTable {
amtConfig.solEnabled,
amtConfig.tenantId,
amtConfig.tlsSigningAuthority,
amtConfig.tlsSigningAuthorityURL,
amtConfig.ieee8021xProfileName,
amtConfig.ipSyncEnabled,
amtConfig.localWifiSyncEnabled
Expand Down Expand Up @@ -297,8 +302,8 @@ export class ProfilesTable implements IProfilesTable {
mebx_password=$6, generate_random_mebx_password=$7,
tags=$8, dhcp_enabled=$9, tls_mode=$10, user_consent=$13,
ider_enabled=$14, kvm_enabled=$15, sol_enabled=$16,
tls_signing_authority=$17, ieee8021x_profile_name=$18,
ip_sync_enabled=$19, local_wifi_sync_enabled=$20
tls_signing_authority=$17, tls_signing_authority_url=$18, ieee8021x_profile_name=$19,
ip_sync_enabled=$20, local_wifi_sync_enabled=$21
WHERE profile_name=$1 and tenant_id = $11 and xmin = $12`,
[
amtConfig.profileName,
Expand All @@ -318,6 +323,7 @@ export class ProfilesTable implements IProfilesTable {
amtConfig.kvmEnabled,
amtConfig.solEnabled,
amtConfig.tlsSigningAuthority,
amtConfig.tlsSigningAuthorityURL,
amtConfig.ieee8021xProfileName,
amtConfig.ipSyncEnabled,
amtConfig.localWifiSyncEnabled
Expand Down
3 changes: 2 additions & 1 deletion src/models/RCS.Config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,8 @@ export enum TlsMode {

export enum TlsSigningAuthority {
SELF_SIGNED = 'SelfSigned',
MICROSOFT_CA = 'MicrosoftCA'
MICROSOFT_CA = 'MicrosoftCA',
CUSTOM_CA = 'Chip2Cloud'
}

export interface connectionParams {
Expand Down
1 change: 1 addition & 0 deletions src/models/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ export class AMTConfiguration {
tlsMode?: TlsMode
tlsCerts?: TLSCerts
tlsSigningAuthority?: TlsSigningAuthority | null
tlsSigningAuthorityURL?: string | null
userConsent?: AMTUserConsent | null
iderEnabled?: boolean
kvmEnabled?: boolean
Expand Down
1 change: 1 addition & 0 deletions src/routes/admin/profiles/amtProfileValidator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ describe('AMT Profile Validation', () => {
it('should pass on creation with valid TLS values', async () => {
req.body.tlsMode = TlsMode.MUTUAL_ONLY
req.body.tlsSigningAuthority = TlsSigningAuthority.MICROSOFT_CA
req.body.tlsSigningAuthorityURL = 'https://www.intel.com'
await testExpressValidatorMiddleware(req, res, amtProfileValidator())
const errors = validationResult(req)
expect(errors.isEmpty()).toBeTruthy()
Expand Down
4 changes: 4 additions & 0 deletions src/routes/admin/profiles/amtProfileValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,10 @@ export const amtProfileValidator = (): ValidationChain[] => [
.optional({ nullable: true })
.isIn(Object.values(TlsSigningAuthority))
.withMessage(`TLS Signing Authority must be one of ${Object.values(TlsSigningAuthority)}`),
check('tlsSigningAuthorityURL')
.optional({ nullable: true })
.matches('^(?:http[s]?://.)?(?:www.)?[-a-zA-Z0-9@%._+~#=]{2,256}.[a-z]{2,6}(?:[-a-zA-Z0-9@:%_+.~#?&//=]*)$')
.withMessage(`TLS Signing Authority URL must be a valid URL`),
check('ciraConfigName')
.optional({ nullable: true })
.custom((value, { req }) => {
Expand Down
5 changes: 4 additions & 1 deletion src/routes/admin/profiles/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ import { NodeForge } from '../../../NodeForge.js'
import { type ISecretManagerService } from '../../../interfaces/ISecretManagerService.js'
import { CertManager } from '../../../certManager.js'
import Logger from '../../../Logger.js'
import { ClientAction, TlsSigningAuthority } from '../../../models/RCS.Config.js'
import { ClientAction, TlsMode, TlsSigningAuthority } from '../../../models/RCS.Config.js'
import { stringify } from 'querystring'

export function adjustTlsConfiguration(amtConfig: AMTConfiguration): AMTConfiguration {
// default to self-signed if tls is indicated
Expand All @@ -27,7 +28,9 @@ export function adjustTlsConfiguration(amtConfig: AMTConfiguration): AMTConfigur
// clear out authority if it shouldn't be there.
if (!amtConfig.tlsMode && amtConfig.tlsSigningAuthority) {
amtConfig.tlsSigningAuthority = null
amtConfig.tlsSigningAuthorityURL = null
}

return amtConfig
}

Expand Down
20 changes: 19 additions & 1 deletion src/routes/admin/profiles/create.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { AMTUserConsent } from '../../../models/index.js'
import { adjustRedirectionConfiguration } from './common.js'
import { jest } from '@jest/globals'
import { type SpyInstance, spyOn } from 'jest-mock'
import { tls } from 'node-forge'

describe('Profiles - Create', () => {
let resSpy
Expand Down Expand Up @@ -182,6 +183,23 @@ describe('Profiles - Create', () => {
...defaultRedirectionCfgACM
})
expect(writeSecretSpy).not.toHaveBeenNthCalledWith(2, `TLS/${req.body.profileName}`, expect.anything())
})
it('should handle error if TLS certificate authority URL is empty', async () => {
req.body = {
...sparseAcmCfg,
tlsMode: TlsMode.SERVER_ALLOW_NONTLS,
tlsSigningAuthority: TlsSigningAuthority.CUSTOM_CA,
verifyTlsSigningAuthorityURL: null
}
await createProfile(req, resSpy)
expect(insertSpy).toHaveBeenCalledWith({
...req.body,
amtPassword: 'AMT_PASSWORD',
mebxPassword: 'MEBX_PASSWORD',

...defaultRedirectionCfgACM
})
expect(resSpy.status).toHaveBeenCalledWith(500)
})
it(`should set default AMT Redirection Configuration settings for ${ClientAction.ADMINCTLMODE}`, async () => {
req.body = {
Expand All @@ -204,7 +222,7 @@ describe('Profiles - Create', () => {
userConsent: AMTUserConsent.ALL
})
})
it('should handle error', async () => {
it('should handle error if insert fails', async () => {
spyOn(req.db.profiles, 'insert').mockResolvedValue(null)
await createProfile(req, resSpy)
expect(insertSpy).toHaveBeenCalledWith({
Expand Down
6 changes: 5 additions & 1 deletion src/routes/admin/profiles/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,12 @@ export async function createProfile(req: Request, res: Response): Promise<void>
throw new Error('Error saving password to secret provider. AMT Profile not inserted')
}
}
// generate self-signed certificates for use with TLS config if applicable
// generate self-signed certificates for use with TLS config if applicable or validate CUSTOM_CA has a TLS Authority URL
if (amtConfig.tlsMode != null) {
if (amtConfig.tlsSigningAuthority === TlsSigningAuthority.CUSTOM_CA && !amtConfig.tlsSigningAuthorityURL) {
throw new Error('Error during TLS signing authority validation. You must provide a valid signing authority URL')
}

// API compatibility: default to self-signed if no other option is indicated
if (!amtConfig.tlsSigningAuthority || amtConfig.tlsSigningAuthority === TlsSigningAuthority.SELF_SIGNED) {
await generateSelfSignedCertificate(req.secretsManager, amtConfig.profileName)
Expand Down
1 change: 1 addition & 0 deletions src/routes/admin/profiles/edit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ export const getUpdatedData = async (newConfig: any, oldConfig: AMTConfiguration
amtConfig.kvmEnabled = newConfig.kvmEnabled ?? oldConfig.kvmEnabled
amtConfig.solEnabled = newConfig.solEnabled ?? oldConfig.solEnabled
amtConfig.tlsSigningAuthority = newConfig.tlsSigningAuthority ?? oldConfig.tlsSigningAuthority
amtConfig.tlsSigningAuthorityURL = newConfig.tlsSigningAuthorityURL ?? oldConfig.tlsSigningAuthorityURL
amtConfig.ieee8021xProfileName = newConfig.ieee8021xProfileName
amtConfig.version = newConfig.version
return amtConfig
Expand Down
Loading