Showing posts with label PKI. Show all posts
Showing posts with label PKI. Show all posts

Thursday, June 23, 2022

PetitPotam Defenses

Protection against coerced authentication on domain controllers:



Print Spooler:


Disable the service via group policy on all DC's

EFS RPC attack:



Create the two RPC filters by putting this in a text file (source):

rpc
filter
add rule layer=um actiontype=block
add condition field=if_uuid matchtype=equal data=c681d488-d850-11d0-8c52-00c04fd90f7e
add filter
add rule layer=um actiontype=block
add condition field=if_uuid matchtype=equal data=df1941c5-fe89-4e79-bf10-463657acf44d
add filter
quit


Save the file and use "netsh -f filename.txt" to apply it


DFS RPC attack:



Create one RPC filter by putting this in a text file (source)

rpc
filter
add rule layer=um actiontype=block
add condition field=if_uuid matchtype=equal data=4fc742e0-4a10-11cf-8273-00aa004ae673
add filter
quit


Save the file and use "netsh -f filename.txt" to apply it

This dfs filter has some impact on creation of new dfs namespaces. Otherwise it doesn't seem to cause other issues that I can tell.


Certificate Authority hardening:


Follow the MS guidance on hardening the CA against NTLM relay. Essentially you configure the web interfaces to allow kerberos only with extended protection. If possible, disable NTLM auth completely on the server. Beyond that, limiting access to client certificates and not allowing user supplied SAN's on them should be done.

Thursday, February 17, 2022

Creating virtual smart card for MIM CM

To use a virtual card on existing profiles that prompt for pin in the certificate manager portal site, use this to create the virtual card:

tpmvscmgr create /name myvsc /pin prompt /adminkey default /generate

When prompted for default admin key, use: 010203040506070801020304050607080102030405060708

When prompted for pin, it will need to be 8 characters long even if it says it can be less than that.

Wednesday, December 29, 2021

Finding expiring certificates in your CA

A while ago, I was working on a method of discovering and creating alerts for expiring smartcards.  While looking at some of the various methods to pull details from FIM certificate manager or the AD certificate services CA that issues the certs, I ended up goinig with certutil as the tool of choice for pulling the data.  The build in filtering of the results helped give the ability to confine the results to certain certificate types, and also to avoid anything that was revoked.  Putting this together with output processing in powershell, it is pretty easy to pull together a list of certs and their expiration time.  Using grouping, you can avoid the problem of having multiple results per user (for those who have already renewed).  Since smartcards use UPN as an identifier, I went with that attribute to help get the user details.  For other use cases that would need to be modifed and the Get-ADUser functionality wouldn't be required.




#this line needs to be modified to target the CA and the OID
#of the cert type that you want to look at (if you are restricting it
#Disposition of 20 means certs that are active
certutil -config "<CA server FQDN>\<CA NAME>" -view -out "user principal name,certificate expiration date" -restrict "certificatetemplate=<templateOID>,Disposition=20"  > .\certdump.txt

$results = @()
$recordbound = $false
Try { $data = get-content .\testcertdump.txt -erroraction stop } catch { 
		#error handling
	}
For ($i=0; $i -lt $data.count; $i++) {
	#process the multiline record to get user UPN account name and certificate expirations
	if ($recordbound) {
		$result = new-object PSobject
		$UPN = $data[$i].substring($data[$i].indexof('"')+1).trim('"')
		$dateval = $data[$i+1].substring($data[$i+1].indexof(":")+1)
		$dateval = [datetime]$dateval
		add-member -input $result NoteProperty UPN $upn
		add-member -input $result NoteProperty Expiration $dateval
		$i = $i+2
		$recordbound = $false
		$results += $result
	}

	#start of a new multiline record
	if ($data[$i] -match "^Row ") {
		$recordbound = $true
	}
}

#User may have renewed before, so there can be more than one cert...so group by user UPN
$groupdata = $results|group UPN
$curdate = get-date

#Look at all certificates for a given user and select the one with the furthest expiration date (I.e. last one issued to this UPN)
$groupdata = $groupdata | Select Name,@{name="expiration";expression={($_.group|sort expiration |select -last 1).expiration}}

foreach ($entry in $groupdata) {
	$debugstr = "$($entry.name)  Expiration $($entry.expiration)"
	$timediff = new-timespan -start $entry.expiration -end $curdate
	$days = 0 - $timediff.days
	if ($days -lt 30) {
		$debugstr += ".  In expiration window."
		#expiration warning, need to find primary account email and send it, if they are still active
		$user = get-aduser -ldapfilter "(&(objectclass=user)(userprincipalname=$($entry.name)))" -properties enabled,manager
		if ($user.enabled) {
			$debugstr += "  Account is enabled."
			#do something with it
		} else {
			$debugstr += " User 431 is disabled, ignoring."
		}
	}
	write-debug $debugstr
}

Wednesday, October 21, 2020

Convert p7b file to CER/PEM/CRT with microsoft gui tools

 Doubleclick the p7b file to open it, expand all the folders.  In the list of certificates, you might see multiple certificates, as p7b files can be a collection of certificates, which often include the full chain of certificates up to the root.  When converting to a CER, PEM, or CRT file, we are making a file with one certificate in it, so you need to select the specific cert you want to create a file for.  In this example, I'm using fiddler's certificate


Double click the cert you want


Click the install certificate button and use the user store.  Change the option to place certificate in a specific folder and select personal from the popup window




Once the certificate is installed, click start->run-> certmgr.msc


Expand the personal->certificates folder.  Right click on the certificate that you just imported, select all tasks -> export

Use the do not export the private key option



Select the DER or Base-64 option.  This will depend on what system you are using and what it supports.  Base-64 is probably the safest option.

Select an export folder and filename for the converted certificate file.  






Thursday, September 26, 2019

FIM or MIM certificate manager client tracing (Cmclient)

I have found that most of the posts you can find regarding setting up trace logging on the CM Client side don't really work.  These are the steps that MS provided to me in a recent case.

1) Open regedit
   a) create key:  [HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\CLM\adk]
   b) create key: [HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\CLM\adk\TraceError]
      i)  Create Reg_DWORD with name "*", and value 0x1
      ii)  create REG_DWORD with name "C:\Program Files (x86)\Internet Explorer\IEXPLORE.EXE", with value 0x1
     iii) create REG_DWORD with name "c:\Program Files (x86)\Microsoft Forefront Identity Manager\2010\CM Client\bin\clmProfileUpdate.exe", with value 0x1

   b) create key [HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\CLM\adk\TraceError\Folder]
    i) create REG_SZ with name "C:\Program Files (x86)\Internet Explorer\iexplore.exe" with value "C:\cmtraces"   (or wherever you want the log file to be created)
    ii)  create REG_SZ with name "C:\Program Files (x86)\Microsoft Forefront Identity Manager\2010\CM Client\bin\clmProfileUpdate.exe"  with value "C:\cmtraces"

Grant permissions to everyone on that file location that you are logging to.

Search the registry under HKCU for "TraceError".  If that exists under a folder structure that has a CLM key folder above it, delete the whole CLM key.


The above registry keys look like its very x86 specific, so similar keys may be needed for x64 client versions or IE.



FIM/MIM certificate manager, can't enroll due to wrong number of attributes

Certificate manager can be picky about x86 and x64 versions of Internet Explorer and the CM client software.  In the past, I've had cases where the x64 client needed to be installed and x64 IE used.  Other times both needed to be x86.  Recently I hit this "wrong number of arguments" error while issuing a card in a newly built environment.  The issue was resolved by running the x64 bit version of IE with the x86 version of the client installed.  For newer windows OS, the link to IE should default to the x64, but older ones may point to x86.  In the two "program files" directories, you can get to the correct .exe version if you really want to make sure you have the right one.


Trace:


"2019-07-07 18:48:53.85 -07" "Microsoft.Clm.BusinessLayer.SmartCard.SmartCard" "Void EnrollFailed(Microsoft.Clm.Common.Requests.Request, System.String, Boolean, System.String)" "CONTOSO\CertAdminGuy" "CONTOSO\CertAdminGuy" 0x000004D8 0x00000004

Enroll sequence failed. Smart Card UUID: c1e07453-4610-46cf-b9f2-4e0b819eda80 OnIntall: False Error: Wrong number of arguments or invalid property assignment

"2019-07-07 18:48:53.95 -07" "Microsoft.Clm.Web.Modules.BaseCspUserControl" "Void ProcessClientMessage(Microsoft.Clm.BusinessLayer.SmartCard.BaseCsp.Serialization.bcspClientMsg)" "CONTOSO\CertAdminGuy" "CONTOSO\CertAdminGuy" 0x000004D8 0x00000004


1) Exception Information

*********************************************
Exception Type: Microsoft.Clm.BusinessLayer.SmartCard.BaseCsp.ClientException
Number: -2146827838
Message: Wrong number of arguments or invalid property assignment
Data: System.Collections.ListDictionaryInternal
TargetSite: Microsoft.Clm.BusinessLayer.SmartCard.BaseCsp.ServerMessage Fail()
HelpLink: NULL
Source: Microsoft.Clm.BusinessLayer



StackTrace Information

*********************************************
   at Microsoft.Clm.BusinessLayer.SmartCard.BaseCsp.EnrollProtocol.Fail()
   at Microsoft.Clm.BusinessLayer.SmartCard.BaseCsp.Protocol.HandleError()
   at Microsoft.Clm.BusinessLayer.SmartCard.BaseCsp.Protocol.ProcessClientMessage()
   at Microsoft.Clm.BusinessLayer.SmartCard.BaseCsp.Protocol.ProcessClientMessage(Guid requestUuid, bcspClientMsg clientMsg)
   at Microsoft.Clm.Web.Modules.BaseCspUserControl.ProcessClientMessage(bcspClientMsg msg)

Upgrade FIM 2010R2 Certificate Manager to MIM 2016 SP1

I recently ran this scenario through a lab, where I had a Windows 2008R2 server with a FIM 2010R2 instance at a pretty low patch level, along with a cm client installed on the same machine.  Going through the upgrade, I followed roughly these steps:

1) Upgrade of the FIM 2010R2 server components to the last released patch level (4.1.3766.0).  This step may not have been necessary, but I did it just in case its relevant.

2) Install .net 4 framework on the CM server and CA if they don't have it already.  It is a prerequisite for MIM 2016 SP1

3) Install of MIM 2016 SP1 CM server component over the top of the existing installation.  The component list of the installer defaults to try to install the CA module component.  You can uncheck that.  There will be a notice about reusing the database and warning regarding that.  The install itself went smoothly.  The only issue on the CM server was that the IIS application pool's identity was changed from my service account to LocalSystem.  So this will need to be manually fixed.  After install of the CM web server components, run the same installer on the certificate authority that you point to.  Again, this was smooth.  You will need to unselect the installer components that you don't want.  There's a checkbox option regarding keeping your old settings.  Restart the cert services when done.  For both of these components, I don't believe a reboot was required (all card operations still worked), however if you run some other installer afterwards it may tell you that a reboot is needed.

4) At this point I did an in-place OS upgrade to 2012R2 on the CM server.  Again, no issues here.  All the components for the server and the cm client were fine after the upgrade.  The only issue was IE security settings for the trusted zone were changed and I had to do some fixes there.

5) Patch both the CM server and CA server to the latest patch level.  In my case I took it directly to 4.5.412.0.  Again, no reboots we required.  Everything continued working fine for card operations that I tested throughout the whole process.

Also note: I did not upgrade the CM client during any of the stages above, while I was still able to perform card enrollment/renewal and such on my physical cards at each step.  For the CM client upgrade, you can't directly upgrade from FIM2010 versions to MIM2016 versions.  You need to uninstall the old client and then put on the 2016 SP1 version.  Surprisingly with these two operations, neither of them required a reboot.  I tried taking this directly to the same MIM patch version of the server, but ran into DLL dependency errors.  So I went to v4.4.1749.0 instead (reboot required).  The few MIM patches released since then have various .net framework version and visual c++ install dependencies, so I'm assuming the client might be impacted by these dependencies, while the server component installers and patches did not require them.

Thursday, March 29, 2018

IIS certificate completion failure 0x80094004

I had this error brought up to me recently as someone was trying to install a certificate that was issued and sent along with CA chain links.  Often certificate providers will include multiple formats as well as certificate chain information, which can lead to some confusion among application owners that aren't so familiar with all aspects of PKI.  Unfortunately this is usually necessary as many different systems have different requirements for setting up certificates, some of which include the need to manually import the chain.

This particular error suggests something is wrong with a detail on the certificate.  After discussing with the application team that was doing the install, it turned out they were trying to complete the request with one of the certificate authority certificates instead of the certificate that was issued for the CSR request.  After clarifying the matter, they were able to install the correct certificate without any issue.


Wednesday, April 19, 2017

Download all enterprise CA crl's from active directory

This script will look for all published crl's in the configuration partition, download them, and write them to binary files.  To further examine the files, you can open them up in windows (standard certificate viewing tools), or use the PSPKI module to dig into the data.


$debase = new-object directoryservices.directoryentry("LDAP://RootDSE")
$configpartition = $debase.configurationNamingContext[0]
$de = new-object directoryservices.directoryentry(` "LDAP://CN=CDP,CN=Public Key Services,CN=Services," + $configpartition)
$ds = new-object directoryservices.directorysearcher($de)
$ds.filter = "(objectclass=cRLDistributionPoint)"
$ds.propertiestoload.add("certificaterevocationlist")|out-null
$crls = $ds.findall()
foreach ($crl in $crls) {
$CAcert = $crl.path.replace("LDAP://CN=","")
$CAcert = $CAcert.substring(0,$CAcert.indexof(","))
$file = $CACert + ".crl"
set-content $file  ([byte[]]($crl.properties.certificaterevocationlist[0])) ` -encoding Byte
}

Friday, November 14, 2014

Slow smartcard logon through remote desktop (RDP)

For anyone that has deployed smartcards, you have probably noticed at some point that smartcard logons are much slower than password logons. When they are done over remote desktop using local smartcard redirection, it can be horribly slow. In my testing, it appeared that whatever the ping response time was (in milliseconds divided by 100) would directly related to how many minutes it would take for me to log onto a remote machine. 200ms being 2 minutes, 800ms being 8minutes. This can cause logons to drop while they are still being processed. If you go searching for details on this problem, there doesn't seem to be much helpful information. Some suggest driver problems can be a factor, and other results may point you to some KB articles for hotfixes such as:

A smart card logon to a terminal session stops responding server that is running Windows Server 2008 and Windows Server 2008 R2
A program that requires you to use a smart card stops responding in a remote desktop connection in Windows Server 2008, in Windows Vista, in Windows 7 or in Windows Server 2008 R2
You may wait for up to 30 seconds when you use a smart card to unlock a computer that is running Windows 7 or Windows Server 2008 R2
Windows 7-based or Windows Server 2008 R2-based Remote Desktop Services server freezes when you try to log on to or log off the server by using a smart card
RDP 8 upgrade

I tried all of these, but none seemed to help. We eventually ended up going through a microsoft support case for the issue, which gave us some more suggested hotfixes to apply in this specific order (none worked):

"0x80100065" error when you call the SCardConnect function in Windows 7, Windows Server 2008 R2, Windows 8, and Windows Server 2012
A computer that has smart card logon enabled stops responding after you remove and then reinsert a smart card in Windows 7, Windows Vista, Windows Server 2008 or Windows Server 2008 R2
"Interactive Logon: Smart card removal behavior" Group Policy setting doesn't work as expected in Windows 7 SP1 or Windows Server 2008 R2 SP1
PIN dialog box appears unexpectedly when you open an encrypted email message after you remove and reinsert a Base CSP smart card in Windows 7 or in Windows Server 2008 R2
The screen saver grace period does not work as expected if the period exceeds 60 seconds on a computer that is running Windows 7 or Windows Server 2008 R2
Number of incorrect PIN retry attempts is less than expected after you unblock a smart card on a computer that is running Windows Vista, Windows Server 2008, Windows 7, or Windows Server 2008 R2

After further debugging and log analysis, the technician told us that the redirection function happens more than 50 times during the logon, with each request being sent individually. Essentially, with all of this back and forth one by one traffic, network latency causes big impact as we had originally reported to them. This was just marked down as expected behaviour that needed to be accepted. Sadly we were left with this situation, however with some further digging around, I did find one obscure forum post for a registry value that I couldn't find documented anywhere on Microsoft (at that time). This value can be created in HKLM\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp. The value is a Dword with the name LogonTimeout, and its value is in seconds. You put this value on the server end, and it will allow the connection to stay open longer during the logon process, so you don't have the connection dropping while its showing you the "welcome" screen. Otherwise you need to provide activity into the RDP connection window to reset the default timer, which I believe is 60 seconds. This activity can be mouse clicks or any other input that would go into the remote session. There is another key that you may want to adjust, which is related to timeouts in the smartcard crypto provider. More on this can be found in this article.

Monday, March 31, 2014

FIM CM Portal problems

Lately I have been working a lot with the FIM CM portal in support of end users trying to perform self service operations in mixed environment of OS's and versions of IE.  Below are some problems seen, and some suggested workarounds that may help others with the same issues.  From experience, it looks like the portal has problems caused by ActiveX security settings, IE compatibility mode required as well as FIM CM client architecture support issues.

Some ways to get around problems with FIM CM portal:

1) CM portal site is in trusted sites, yet user is getting repeat prompts for logon to the page.  The OS security logs on the portal server show success, yet IIS is not accepting it and ends up at access denied.

Solution to try:  Internet Explorer options -> Security tab ->  Check "Enable Protected Mode", and set security levels to Low.  Restart IE


2)  User is able to get into FIM CM portal, but whenever they click on an operation, nothing happens.  Problem with javascript in the links

Solutions to try:
a) Set compatibility mode for the site.  In newer versions of IE, you can find this in the tools menu
b) Internet Explorer options -> Security tab -> Set security level to Low.  Refresh the page


3) BaseCSP error on smart card operations

Solutions to try:
a)  For XP machines, ensure the BaseCSP hotfix is installed (KB909520)
b)  Ensure the FIM CM Client is installed (displays as "Forefront Identity Manager CM Client" in add/remove programs)
c)  Internet Explorer options -> Security tab -> Set security level to Low.  Refresh the page
d)  If the client machine is x64 bit OS
    1) Check the version of the installed FIM client (what "program files" folder is it under, x86 or the main one).  Try to run the IE version that matches the version of the FIM client
    2)  (IE11) Internet options -> Advanced tab -> Check "Enable 64-bit processes for enhanced protected mode" or "Enabled Enhanced Protected Mode" if you don't have the first option.  Do this if you have the 64 bit FIM CM Client and are running IE 64bit, yet it still fails.
    3)  If you have the 64 bit client installed, and both versions of IE fail, and step #2 isn't available, remove the 64 bit client and install the 32bit client
e)  Ensure ActiveX filtering is off.  This may show up in the address bar as an icon saying components are filtered.  Or you can look in the tools menu to see if it is checked (not all versions of IE have this)
e)  Repair or reinstall the FIM CM client


4) Slow/hanging operations.  Look at 64bit/32bit IE as mentioned in BaseCSP problems.  You may want to try the other version of IE.

Thursday, February 20, 2014

Finding expiring smartcards (or other certificates) on the CA

Recently I was working on a method of discovering and creating alerts for expiring Smartcards.  While looking at some of the various methods to pull details from FIM certificate manager or the AD certificate services CA that issues the certs, I ended up goinig with certutil as the tool of choice for pulling the data.  The build in filtering of the results helped give the ability to confine the results to certain certificate types, and also to avoid anything that was revoked.  Putting this together with output processing in Powershell, it is pretty easy to pull together a list of certs and their expiration time.  Using grouping, you can avoid the problem of having multiple results per user (for those who have already renewed).  Since Smartcards use UPN as an identifier, I went with that attribute to help get the user details.  For other use cases that would need to be modified and the Get-ADUser functionality wouldn't be required.



#this line needs to be modified to target the CA and the OID
#of the cert type that you want to look at (if you are restricting it
#Disposition of 20 means certs that are active
certutil -config "<CA server FQDN>\<CA NAME>" -view -out "user principal name,certificate expiration date" -restrict "certificatetemplate=<templateOID>,Disposition=20"  > .\certdump.txt

$results = @()
$recordbound = $false
Try { $data = get-content .\certdump.txt -erroraction stop } catch { 
  #error handling
 }
For ($i=0; $i -lt $data.count; $i++) {
 #process the multiline record to get user UPN account name and certificate expirations
 if ($recordbound) {
  $result = new-object PSobject
  $UPN = $data[$i].substring($data[$i].indexof('"')+1).trim('"')
  $dateval = $data[$i+1].substring($data[$i+1].indexof(":")+1)
  $dateval = [datetime]$dateval
  add-member -input $result NoteProperty UPN $upn
  add-member -input $result NoteProperty Expiration $dateval
  $i = $i+2
  $recordbound = $false
  $results += $result
 }

 #start of a new multiline record
 if ($data[$i] -match "^Row ") {
  $recordbound = $true
 }
}

#User may have renewed before, so there can be more than one cert...so group by user UPN
$groupdata = $results|group UPN
$curdate = get-date

#Look at all certificates for a given user and select the one with the furthest expiration date (I.e. last one issued to this UPN)
$groupdata = $groupdata | Select Name,@{name="expiration";expression={($_.group|sort expiration |select -last 1).expiration}}

foreach ($entry in $groupdata) {
 $debugstr = "$($entry.name)  Expiration $($entry.expiration)"
 $timediff = new-timespan -start $entry.expiration -end $curdate
 $days = 0 - $timediff.days
 if ($days -lt 30) {
  $debugstr += ".  In expiration window."
  #expiration warning, need to find primary account email and send it, if they are still active
  $user = get-aduser -ldapfilter "(&(objectclass=user)(userprincipalname=$($entry.name)))" -properties enabled,manager
  if ($user.enabled) {
   $debugstr += "  Account is enabled."
   #do something with it
  } else {
   $debugstr += " User 431 is disabled, ignoring."
  }
 }
 write-debug $debugstr
}

Tuesday, September 3, 2013

FIM Certificate manager portal "Value does not fall within the expected range"

Recently I ran into an unusual issue with a FIM certificate manager portal installation occasionally throwing the "Value does not fall within the expected range" error when doing searches.  Some searches would work all of the time, while others would fail all of the time.


The error:

1) Exception Information
*********************************************
Exception Type: System.ArgumentException
Message: Value does not fall within the expected range.
ParamName: NULL
Data: System.Collections.ListDictionaryInternal
TargetSite: Int32 SecurityDescriptorToBinarySD(Microsoft.Clm.Security.Structs.VariantIDispatch, IntPtr ByRef, UInt32 ByRef, System.String, System.String, System.String, UInt32)
HelpLink: NULL
Source: Microsoft.Clm.Security.Authorization

StackTrace Information
*********************************************
   at Microsoft.Clm.Security.NativeMethods.SecurityDescriptorToBinarySD(VariantIDispatch vVarSecDes, IntPtr& ppSecurityDescriptor, UInt32& pdwSDLength, String pszServerName, String userName, String passWord, UInt32 dwFlags)
   at Microsoft.Clm.Security.Authorization.SecurityDescriptor.ConvertToByteArray(DirectoryEntry entry)



After digging through various components, checking AD, etc, a pattern seemed to emerge.  Whenever the search result should have returned results of users that were in a specific OU, it would fail.  While results that gave only results in other OU's would work.  On checking the metadata for the OU, the ntSecurityDescriptor had recently changed right around the time that the FIM CM portal started throwing errors.  A large number of property management ACE's had been added, which pushed the size of the ACL too high for the system to deal with.  According to Microsoft, the max size for an ACL is 64k.  My previous post shows how easy it can be to hit that limit when you get too fine grained in your entries.  Removing the added ACE's resolved the issue.

Wednesday, March 3, 2010

Checking SSL certificate values with Powershell

For anyone that needs to check SSL certificates in a simple way from Powershell, I created something for this purpose a while back. It works for most SSL connections using .NET code and will throw exceptions if the name on the cert you provide is not valid, or the cert is expired.

Check-sslcert.ps1 (Updated Jan 15, 2013)


#Requires -version 2.0
 
param(
 [parameter(mandatory=$true,helpmessage="IP address or hostname to resolve remote system")][string]$ipaddr,
 [parameter(mandatory=$true,helpmessage="TCP port number that SSL application is listening on")][int]$port,
 [parameter(helpmessage="Hostname on certificate")][string]$myhostname=$ipaddr,
 [parameter(helpmessage="Verbose")][alias('fulldetail')][switch]$V
 
)


function stripcomma([string]$tempstring) {
 write-debug "In Function StripComma $($tempstring)"
 return $tempstring.replace(',',';') 
 
}

function convertoid([string]$oid) {
 write-debug "In function ConvertToOID: $($oid)"
 #strip off oid component common to all crypto types
 $oidstr = $oid.replace("1.2.840.113549.1.","")
 
 #pull out first number
 $firstval = $oidstr.substring(0,$oidstr.indexof('.'))
 
 #pull out second number for more detail
 $sub = $oidstr.substring(2)
 if ($sub.indexof('.') -gt 0) {
  $sub = $sub.substring(0,$sub.indexof('.')) 
 }
 
 if ($firstval -eq "1") {
  $format = "PKCS-1"
  switch ($sub) {
   "1" { return ($format + " RSA Encryption") }
   "2" { return ($format + " MD2 with RSA") }
   "3" { return ($format + " rsadsi md4 with RSA")}
   "4" { return ($format + " MD5 with RSA") }
   "5" { return ($format + " SHA-1 with RSA") }
   "6" { return ($format + " rsaOAEPEncryptionSet")}
   "11" { return ($format + " sha256 with RSA") }
  }
 } elseif ($firstval -eq "5") {
  $format = "RSA PKCS5"
  switch ($sub) {
   "1" { return ($format + " rsadsi pbe with MD2 DES-CBC")}
   "3" { return ($format + " rsadsi pbe with MD5 DES-CBC")}
   "4" { return ($format + " pbe with MD2 and RC2_CBC")}
   "6" { return ($format + " pbe with MD5 and RC2_CBC")}
   "9" { return ($format + " pbe with MD5 and XOR")}
   "10" { return ($format + " pbe with SHA1 and DES-CBC")}
   "11" { return ($format + " pbe with SHA1 and RC2_CBC")}
   "12" { return ($format + " id-PBKDF2 key derivation function")}
   "13" { return ($format + " id-PBES2  PBES2 encryption")}
   "14" { return ($format + " id-PBMAC1 message auth scheme")}
   
  }
 } elseif ($firstval -eq "7" ) {
  $format = "PKCS-7"
  switch ($sub) {
   "1" { return ($format + " data")}
   "2" { return ($format + " signed data")}
   "3" { return ($format + " enveloped data")}
   "4" { return ($format + " signed and enveloped data")}
   "5" { return ($format + " digested data")}
   "6" { return ($format + " encrypted data")}
  }
 } elseif ($firstval -eq "12") {
  return ("PKCS-12")
 } elseif ($firstval -eq "15") {
  return ("PKCS-15") 
 } else {
  return $oid 
 }
   
 
}

######
#MAIN#
######

#open TCP connection
try {
 $conn = new-object system.net.sockets.tcpclient($ipaddr,$port) 
 
 try {
  #create ssl stream on existing tcp connection
  $stream = new-object system.net.security.sslstream($conn.getstream())
  #send hostname on cert to try SSL negotiation
  $stream.authenticateasclient($myhostname) 
  
  $cert = $stream.get_remotecertificate()
  $cert2 = New-Object system.security.cryptography.x509certificates.x509certificate2($cert)    #can get much more information with this class    

  $validto = [datetime]::Parse($cert.getexpirationdatestring())
  $validfrom = [datetime]::Parse($cert.geteffectivedatestring())
  
  if ($V) {
   new-object psobject -property @{ 
    Connection = "Success"
    Machine = $ipaddr
    CertFormat = ($cert.getformat())
    CertExpiration = $validto
    CertIssueDate = $validfrom
    CertIssuer = ($cert.get_issuer())
    SerialNumber = ($cert.getserialnumberstring())
    CertSubject = (stripcomma $cert.get_subject())
    CertType =  (convertoid $cert.getkeyalgorithm())
   }
  } else {
   #non verbose
   New-Object psobject -Property @{
    Connection = "Success"
    Machine = $ipaddr
    CertExpiration = $validto
   }
  }

 } catch {
  #if SSL connection failed, cert may be invalid or name on cert didn't match, fails either way
  throw $_
 } finally {
  Write-Debug "In finally: closing connection"
  $conn.close()
 }
} catch {
 Write-Verbose "Error occurred connecting to $($ipaddr)"
 New-Object PSObject -Property @{
  Machine = $ipaddr
  Connection = "Failure"
  Status = $_.exception.innerexception.message
 }
 
}