Problems with SSL certificates with missing common name and alternative name
gunhanoral opened this issue · 10 comments
If the common name is empty for the certificate, pygnmi fails due to this line.
>>> ssl_cert_deserialized
<Certificate(subject=<Name(<<redacted>>)>, ...)>
>>> ssl_cert_deserialized.subject.get_attributes_for_oid(x509.oid.NameOID.COMMON_NAME)
[]
I bypassed this using an if-else block, manually setting ssl_target_name_override. But this time pygnmi failed due to alternative name.
>>> ssl_cert_subject_alt_names = ssl_cert_deserialized.extensions.get_extension_for_oid(x509.oid.ExtensionOID.SUBJECT_ALTERNATIVE_NAME)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/redacted/redacted/.virtualenvs/redacted/lib/python3.8/site-packages/cryptography/x509/extensions.py", line 125, in get_extension_for_oid
raise ExtensionNotFound("No {} extension was found".format(oid), oid)
cryptography.x509.extensions.ExtensionNotFound: No <ObjectIdentifier(oid=2.5.29.17, name=subjectAltName)> extension was found
I tried this with a second certificate we use on some other devices and it failed with the same error.
I'm not sure what is missing here but I am using the same certificates with other gnmi tools in production so I don't think there's something wrong with them.
hey @gunhanoral ,
cam you please post content of your certificate here (CN and Subject Alternative Names)?
Best,
Anton
Hello @akarneliuk
There's no SAN in the certificates we use.
And commonName is empty "commonName": ""
I don't think I can share any more information, sorry.
Hey @gunhanoral ,
I tried to create certificate without CN, but I'm getting errors:
#security pki certificate generate self-signed empty.pem key gnmi_api.key
Common Name for use in subject:
% Error generating certificate (Common Name is needed)
So I tried to create such:
dev-pygnmi-eos-001#show management security ssl certificate empty.pem
Certificate empty.pem:
Version: 3
Serial Number: 96fede194f849f23
Issuer:
Common name: ""
Validity:
Not before: Jul 14 17:46:19 2022 GMT
Not After: Jul 14 17:46:19 2023 GMT
Subject:
Common name: ""
Subject public key info:
Encryption Algorithm: RSA
Size: 4096 bits
Public exponent: 65537
Modulus: 8fb49a08c950216e0e38b31b5199683e367a5c81586caf1c1b14040
ebb0b931f93a77fc42547dd044f056699af344c2db40639728c1902
7cfe2cdde36a8ae04c1a7863ae92ed7cba710d2b27a20e0bee697d9
b2672df2046877e0f5c8c8e8b0adac54008547ce44d00d750deae2d
c3005858ecf6b0cca2d10d88cffa63937964bf6da0701cdccf99b9f
decec67757265ced02cc19931327c764d6f9d85598a645162cebaba
51bb3a309b902e3fc4ed097355636f2124c0744f5c76f51021aa4f6
67c8edce039f24a6432e94c9f2eb81a4b09dd119a3de7d279007f61
8b03d6d70a1fbc9332fa5bb4e96d1d7efe283db01687c221408e5b7
0969894769f142c7e3a10ea3dab9800bd04f761c70495dddc36922f
dc8ca588594e9b826050f31e95e13f3e334fa976a9efe74abd732fb
b44360580a35ad3c661377ce7a06694a36238a156ad8dd094342e35
832fe558d1cec4bfddb253facda639ec24a3a1f6edcb36c4dcde9bd
f874720ffddbe074c9679234e27bed77af1d223f2098bc29086b423
32bf7f1e720b5c563c7acf06fff3e74453518fed092ff80dacd8ccc
ca9d465621b57aa4469cc3cf8e62fefe0ec5237c95151aaa6d05ea7
83a82b4ed321b923f82ed7e9564759a24cf7a14f41ebe04fd948137
6302831b576b952454f167850f77037a23880306d139d63a6f76c34
69980054f00a8bd8db28c4465e4a58a1dd
However, here we still have CN, which value is ""
, so it is NOT empty. I will try to work it out it and let you know my results, but so far I'm a bit puzzled how your solution works.
Best,
Anton
Hey @gunhanoral ,
Please, try the newest version 0.7.4
, that shall be working for you, if my assumption above was accurate.
Best,
Anton
Hello @akarneliuk sorry I can't confirm if this solves the issue. I don't get any more errors due to common name or san but I can't connect to the device using pygnmi. At this point I'm not sure if this is related to this issue. Maybe I'm mixing up certificates?
This is the script that I'm running:
# Modules
from pygnmi.client import gNMIclient
from getpass import getpass
import os
# Variables
host = ('redacted', 'redacted')
ssl = {
'path_root': os.path.join(os.getenv('SSLDIR'), 'certs', 'ca.crt'),
'path_key': os.path.join(os.getenv('SSLDIR'), 'keys', 'client.key'),
'path_cert': os.path.join(os.getenv('SSLDIR'), 'certs', 'client.crt')
}
# Body
if __name__ == '__main__':
with gNMIclient(target=host, username=os.getenv('USER'), password=getpass(), skip_verify=True, **ssl) as gc:
result = gc.get(path=['/interfaces/interface[name=Ethernet1]/state'])
print(result)
Output:
❯ python3 /tmp/test.py
Password:
Cannot get Common Name: list index out of range
Cannot get Subject Alternative Names: No <ObjectIdentifier(oid=2.5.29.17, name=subjectAltName)> extension was found
ssl_target_name_override is applied, should be used for testing only!
ERROR:root:Failed to setup gRPC channel, trying change cipher
Traceback (most recent call last):
File "/Users/redacted/.virtualenvs/redacted/lib/python3.8/site-packages/pygnmi/client.py", line 223, in wait_for_connect
grpc.channel_ready_future(self.__channel).result(timeout=timeout)
File "/Users/redacted/.virtualenvs/redacted/lib/python3.8/site-packages/grpc/_utilities.py", line 139, in result
self._block(timeout)
File "/Users/redacted/.virtualenvs/redacted/lib/python3.8/site-packages/grpc/_utilities.py", line 85, in _block
raise grpc.FutureTimeoutError()
grpc.FutureTimeoutError
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/tmp/test.py", line 16, in <module>
with gNMIclient(target=host, username=os.getenv('USER'), password=getpass(), skip_verify=True, **ssl) as gc:
File "/Users/redacted/.virtualenvs/redacted/lib/python3.8/site-packages/pygnmi/client.py", line 99, in __enter__
return self.connect()
File "/Users/redacted/.virtualenvs/redacted/lib/python3.8/site-packages/pygnmi/client.py", line 213, in connect
self.wait_for_connect(timeout)
File "/Users/redacted/.virtualenvs/redacted/lib/python3.8/site-packages/pygnmi/client.py", line 230, in wait_for_connect
grpc.channel_ready_future(self.__channel).result(timeout=timeout)
File "/Users/redacted/.virtualenvs/redacted/lib/python3.8/site-packages/grpc/_utilities.py", line 139, in result
self._block(timeout)
File "/Users/redacted/.virtualenvs/redacted/lib/python3.8/site-packages/grpc/_utilities.py", line 85, in _block
raise grpc.FutureTimeoutError()
grpc.FutureTimeoutError
An example of gnmic output using the same certificates:
❯ gnmic -a redacted:redacted get --path "/interfaces/interface[name=Ethernet1]/state" -u redacted --tls-ca $SSLDIR/certs/ca.crt --tls-cert $SSLDIR/certs/client.crt --tls-key $SSLDIR/keys/client.key --skip-verify
failed loading config file: open : no such file or directory
password:
[
{
"time": "1970-01-01T02:00:00+02:00",
"updates": [
{
"Path": "interfaces/interface[name=Ethernet1]/state",
"values": {
"interfaces/interface/state": {
"arista-intf-augments:inactive": false,
"openconfig-interfaces:admin-status": "UP",
"openconfig-interfaces:counters": {
"in-broadcast-pkts": "38901",
"in-discards": "0",
"in-errors": "0",
"in-fcs-errors": "0",
"in-multicast-pkts": "1228474",
"in-octets": "66497837150590",
"in-unicast-pkts": "273129392409",
"out-broadcast-pkts": "2399338480",
"out-discards": "1499",
"out-errors": "0",
"out-multicast-pkts": "138494649",
"out-octets": "104862819133032",
"out-unicast-pkts": "294719493758"
},
"openconfig-interfaces:enabled": true,
"openconfig-interfaces:ifindex": 1,
"openconfig-interfaces:last-change": "1639769865809263872",
"openconfig-interfaces:mtu": 9236,
"openconfig-interfaces:name": "Ethernet1",
"openconfig-interfaces:oper-status": "UP",
"openconfig-interfaces:type": "iana-if-type:ethernetCsmacd",
"openconfig-platform-port:hardware-port": "Port1",
"openconfig-vlan:tpid": "openconfig-vlan-types:TPID_0X8100"
}
}
}
]
}
]
Thank you for your time
Gunhan
Hey @gunhanoral ,
Thanks for sharing this. Could you please advise if override
as you did it before still working?
Best,
Anton
Hey @gunhanoral ,
I did a few more tests, please check the latest #82 and published pygnmi==0.8.2
. I believe it shall be doing what you aimed to have: override target to '' in case your certificate doesn't have CN and SARs. However, I didn't get that working with my test device, as device doesn't like an empty cert. The override though is tested and worked.
Best,
Anton
Hello @akarneliuk ,
Sorry, it failed with another kind of error this time. I tried with override option, with same results.
❯ python3 /tmp/test.py
Password:
Cannot get Common Name: list index out of range
Cannot get Subject Alternative Names: No <ObjectIdentifier(oid=2.5.29.17, name=subjectAltName)> extension was found
ssl_target_name_override is applied, should be used for testing only!
E0723 19:51:08.863921000 123145395400704 ssl_transport_security.cc:1702] Invalid server name indication .
E0723 19:51:08.863952000 123145395400704 ssl_security_connector.cc:135] Handshaker creation failed with error TSI_INTERNAL_ERROR.
E0723 19:51:08.902530000 123145395400704 subchannel.cc:981] subchannel 0x7f9eb5043a30 {address=ipv4:<redacted>:<redacted>, args={grpc.client_channel_factory=0x7f9eb523d160, grpc.default_authority=, grpc.http2_scheme=https, grpc.internal.channel_credentials=0x7f9eb521fb20, grpc.internal.security_connector=0x7f9eb503fd00, grpc.internal.subchannel_pool=0x7f9eb5255590, grpc.primary_user_agent=grpc-python/1.47.0, grpc.resource_quota=0x7f9eb524d310, grpc.server_uri=dns:///<redacted>:<redacted>, grpc.ssl_target_name_override=}}: error initializing subchannel stack: {"created":"@1658595068.902461000","description":"Auth context missing from client auth filter args","file":"src/core/lib/transport/error_utils.cc","file_line":167,"grpc_status":3}
E0723 19:51:08.902722000 123145395400704 combiner.cc:150] assertion failed: last & STATE_UNORPHANED
[1] 33493 abort python3 /tmp/test.py
Hey @gunhanoral ,
This message is quite interesting:
"description":"Auth context missing from client auth filter args
So basically it suggests something is missing in authentication. If you cannot discuss something in public, you can reach me in DM here or in LinkedIn. It is at the moment a bit difficult to troubleshoot your scenario, because I cannot reproduce your issue.
Are using mTLS?
Best,
Anton
Hey @gunhanoral ,
after further tests, we've figured that this is not a Python problem but rather underlying C library, which handles gRPC connection. It doesn't have API to disable the validation entirely; hence, with the existing certificate I don't believe it will work, I'm afraid.
The reason why gnmic working is that because it doesn't rely on the Google's C gRPC library.
Best,
Anton