Skip to content

T7635: OpenConnect Certificate Authentication #4618

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: current
Choose a base branch
from

Conversation

giga1699
Copy link
Contributor

@giga1699 giga1699 commented Jul 24, 2025

Change summary

Adds feature to enable certificate based authentication for OpenConnect

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Code style update (formatting, renaming)
  • Refactoring (no functional changes)
  • Migration from an old Vyatta component to vyos-1x, please link to related PR inside obsoleted component
  • Other (please describe):

Related Task(s)

https://vyos.dev/T7635

Related PR(s)

vyos/vyos-documentation#1662

How to test / Smoketest result

configure
run generate pki ca install catest
commit
run generate pki certificate sign catest install certtest
commit
set vpn openconnect authentication mode certificate cn
set vpn openconnect network-settings client-ip-settings subnet 192.168.1.0/24
set vpn openconnect ssl ca-certificate catest
set vpn openconnect ssl certificate certtest
commit
exit

Check ocserv.conf for auth = "certificate" and cert-user-oid = 2.5.4.3

sudo cat /var/run/ocserv/ocserv.conf

Checklist:

  • I have read the CONTRIBUTING document
  • I have linked this PR to one or more Phabricator Task(s)
  • I have run the components SMOKETESTS if applicable
  • My commit headlines contain a valid Task id
  • My change requires a change to the documentation
  • I have updated the documentation accordingly

Copy link

github-actions bot commented Jul 24, 2025

👍
No issues in PR Title / Commit Title

@giga1699
Copy link
Contributor Author

I believe this would be backwards compatible to Sagitta if you'd like to backport it.

@sever-sever sever-sever requested a review from Copilot July 27, 2025 15:38
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR implements certificate-based authentication for OpenConnect VPN by adding support for client certificate validation. The implementation allows users to configure certificate authentication using Common Name (CN) or UID fields from client certificates.

  • Adds certificate authentication mode with support for CN and UID certificate fields
  • Updates authentication mode validation to handle the new certificate option
  • Requires CA certificate configuration when using certificate authentication

Reviewed Changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
src/conf_mode/vpn_openconnect.py Adds certificate authentication validation logic and mutual exclusion checks
interface-definitions/vpn_openconnect.xml.in Defines the new certificate authentication configuration option
data/templates/ocserv/ocserv_config.j2 Updates the ocserv configuration template to output certificate authentication settings

Comment on lines 107 to 114
'local' in ocserv['authentication']['mode']
and 'radius' in ocserv['authentication']['mode']
or
'local' in ocserv['authentication']['mode']
and 'cert' in ocserv['authentication']['mode']
or
'radius' in ocserv['authentication']['mode']
and 'cert' in ocserv['authentication']['mode']
Copy link
Preview

Copilot AI Jul 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logical operators 'or' and 'and' have different precedence, which may cause unexpected behavior. The condition should be properly grouped with parentheses to ensure correct evaluation: or ('local' in ocserv['authentication']['mode'] and 'cert' in ocserv['authentication']['mode'])

Suggested change
'local' in ocserv['authentication']['mode']
and 'radius' in ocserv['authentication']['mode']
or
'local' in ocserv['authentication']['mode']
and 'cert' in ocserv['authentication']['mode']
or
'radius' in ocserv['authentication']['mode']
and 'cert' in ocserv['authentication']['mode']
('local' in ocserv['authentication']['mode']
and 'radius' in ocserv['authentication']['mode'])
or
('local' in ocserv['authentication']['mode']
and 'cert' in ocserv['authentication']['mode'])
or
('radius' in ocserv['authentication']['mode']
and 'cert' in ocserv['authentication']['mode'])

Copilot uses AI. Check for mistakes.

Comment on lines 121 to 123
ocserv['authentication']['mode']['cert'] = '2.5.4.3'
elif 'uid' in ocserv['authentication']['mode']['cert']:
ocserv['authentication']['mode']['cert'] = '0.9.2342.19200300.100.1.1'
Copy link
Preview

Copilot AI Jul 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code modifies the configuration dictionary during verification, which is incorrect. The verification function should only validate the configuration, not modify it. The OID mapping should be handled in the template or a separate processing step.

Suggested change
ocserv['authentication']['mode']['cert'] = '2.5.4.3'
elif 'uid' in ocserv['authentication']['mode']['cert']:
ocserv['authentication']['mode']['cert'] = '0.9.2342.19200300.100.1.1'
pass # Validation logic for 'cn' can be added here if needed
elif 'uid' in ocserv['authentication']['mode']['cert']:
pass # Validation logic for 'uid' can be added here if needed

Copilot uses AI. Check for mistakes.

Comment on lines 121 to 123
ocserv['authentication']['mode']['cert'] = '2.5.4.3'
elif 'uid' in ocserv['authentication']['mode']['cert']:
ocserv['authentication']['mode']['cert'] = '0.9.2342.19200300.100.1.1'
Copy link
Preview

Copilot AI Jul 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code modifies the configuration dictionary during verification, which is incorrect. The verification function should only validate the configuration, not modify it. The OID mapping should be handled in the template or a separate processing step.

Suggested change
ocserv['authentication']['mode']['cert'] = '2.5.4.3'
elif 'uid' in ocserv['authentication']['mode']['cert']:
ocserv['authentication']['mode']['cert'] = '0.9.2342.19200300.100.1.1'
pass # OID mapping will be handled in a separate step
elif 'uid' in ocserv['authentication']['mode']['cert']:
pass # OID mapping will be handled in a separate step

Copilot uses AI. Check for mistakes.

<description>Custom OID in dotted decimal format</description>
</valueHelp>
<constraint>
<regex>(^\.?\d{1,5}(?:\.\d{1,5})*$|cn|uid)</regex>
Copy link
Preview

Copilot AI Jul 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The regex pattern allows OIDs starting with a dot (e.g., '.1.2.3'), but standard OID notation should not start with a dot. The pattern should be (^\d{1,5}(?:\.\d{1,5})*$|cn|uid) to only allow valid OID formats.

Suggested change
<regex>(^\.?\d{1,5}(?:\.\d{1,5})*$|cn|uid)</regex>
<regex>(^\d{1,5}(?:\.\d{1,5})*$|cn|uid)</regex>

Copilot uses AI. Check for mistakes.

@giga1699 giga1699 force-pushed the T7635 branch 3 times, most recently from ae471d3 to 96d74db Compare July 27, 2025 16:50
@giga1699
Copy link
Contributor Author

Updates made based off Copilot review feedback.

<help>Use certificate based authentication</help>
<valueHelp>
<format>cn</format>
<description>OID 2.5.4.3 - Common Name</description>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My feeling is that these should be sub-nodes like cert cn oc.example.com. That way it would be more obvious to config readers what field of the cert it's supposed to match, and it will be possible to add separate constraints for CNs and UIDs.

I also don't know if help strings should mention OIDs. End users normally talk about symbolic names like CN, I can't see how OIDs could be important or useful here in help strings.

Copy link
Member

@sever-sever sever-sever Aug 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about using certificate instead of cert ?
And common-name instead of cn

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The actual config is the OID, not a name. I don't think you can have more than one selection. I was referencing the OIDs because that's how the example config references that config item. So I don't think putting a domain name in there would be useful, and might lead to confusion by the user.

The OID definition is what openconnect should list as the username in the output of the show commands, and be used for any user specific configurations. The server will validate the user's certificate against the CA that's defined in the configuration to make sure the certificate is valid.

I suppose I figured seeing OIDs in the help might key in a more advanced user that they can certainly specify a specific OID for the configuration to match on. I think CN is going to be the most common use case, but the two listed in the openconnect example configs were CN and UID.

I don't see any issue using certificate instead of cert. I will make that change at a minimum.

I don't have any issue taking out the OID references from the help text if you'd rather them not be in there.

Here's the section from the example config taken from https://github.com/openconnect/ocserv/blob/master/doc/sample.config

# The object identifier that will be used to read the user ID in the client 
# certificate. The object identifier should be part of the certificate's DN
# Useful OIDs are: 
#  CN = 2.5.4.3, UID = 0.9.2342.19200300.100.1.1, SAN(rfc822name)
cert-user-oid = 0.9.2342.19200300.100.1.1

Copy link

CI integration ❌ failed!

Details

CI logs

  • CLI Smoketests (no interfaces) ❌ failed
  • CLI Smoketests (interfaces only) ❌ failed
  • Config tests ❌ failed
  • RAID1 tests ❌ failed
  • TPM tests ❌ failed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging this pull request may close these issues.

3 participants